Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[UXE-5890][UXE-5891] feat: migrate edge functions create/edit pages to api v4 #2034

Merged
merged 2 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/router/routes/edge-functions-routes/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as Helpers from '@/helpers'

import * as EdgeFunctionsService from '@/services/edge-functions-services'
import * as EdgeFunctionsServiceV4 from '@/services/edge-functions-services/v4'

/** @type {import('vue-router').RouteRecordRaw} */
Expand Down Expand Up @@ -31,7 +30,7 @@ export const edgeFunctionsRoutes = {
name: 'create-edge-functions',
component: () => import('@views/EdgeFunctions/CreateView.vue'),
props: {
createEdgeFunctionsService: EdgeFunctionsService.createEdgeFunctionsService
createEdgeFunctionsService: EdgeFunctionsServiceV4.createEdgeFunctionsService
},
meta: {
breadCrumbs: [
Expand All @@ -51,8 +50,8 @@ export const edgeFunctionsRoutes = {
name: 'edit-edge-functions',
component: () => import('@views/EdgeFunctions/EditView.vue'),
props: {
loadEdgeFunctionsService: EdgeFunctionsService.loadEdgeFunctionsService,
editEdgeFunctionsService: EdgeFunctionsService.editEdgeFunctionsService,
loadEdgeFunctionsService: EdgeFunctionsServiceV4.loadEdgeFunctionService,
editEdgeFunctionsService: EdgeFunctionsServiceV4.editEdgeFunctionsService,
updatedRedirect: 'list-edge-functions'
},
meta: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import * as Errors from '@/services/axios/errors'
import { AxiosHttpClientAdapter } from '../../axios/AxiosHttpClientAdapter'
import { makeEdgeFunctionsBaseUrl } from './make-edge-functions-base-url'
import { extractApiError } from '@/helpers/extract-api-error'

export const createEdgeFunctionsService = async (payload) => {
let httpResponse = await AxiosHttpClientAdapter.request({
url: `${makeEdgeFunctionsBaseUrl()}`,
method: 'POST',
body: adapt(payload)
})

return parseHttpResponse(httpResponse)
}

const adapt = (payload) => {
const parsedArgs = JSON.parse(payload.args)
return {
name: payload.name,
code: payload.code,
language: payload.language,
initiator_type: payload.initiatorType,
json_args: parsedArgs,
active: payload.active
}
}

/**
* @param {Object} httpResponse - The HTTP response object.
* @param {Object} httpResponse.body - The response body.
* @param {String} httpResponse.statusCode - The HTTP status code.
* @returns {string} The result message based on the status code.
* @throws {Error} If there is an error with the response.
*/
const parseHttpResponse = (httpResponse) => {
switch (httpResponse.statusCode) {
case 202:
return {
feedback: 'Your edge function has been created',
urlToEditView: `/edge-functions/edit/${httpResponse.body.data.id}`,
functionId: httpResponse.body.data.id
}
case 500:
throw new Errors.InternalServerError().message
default:
throw new Error(extractApiError(httpResponse)).message
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import * as Errors from '@/services/axios/errors'
import { AxiosHttpClientAdapter } from '../../axios/AxiosHttpClientAdapter'
import { makeEdgeFunctionsBaseUrl } from './make-edge-functions-base-url'
import { extractApiError } from '@/helpers/extract-api-error'

export const editEdgeFunctionsService = async (payload) => {
const parsedPayload = adapt(payload)
let httpResponse = await AxiosHttpClientAdapter.request({
url: `${makeEdgeFunctionsBaseUrl()}/${payload.id}`,
method: 'PATCH',
body: parsedPayload
})

return parseHttpResponse(httpResponse)
}

/**
* @param {Object} httpResponse - The HTTP response object.
* @param {Object} httpResponse.body - The response body.
* @param {String} httpResponse.statusCode - The HTTP status code.
* @returns {string} The result message based on the status code.
* @throws {Error} If there is an error with the response.
*/
const parseHttpResponse = (httpResponse) => {
switch (httpResponse.statusCode) {
case 202:
return 'Your edge function has been updated'
case 500:
throw new Errors.InternalServerError().message
default:
throw new Error(extractApiError(httpResponse)).message
}
}

const adapt = (payload) => {
const parsedArgs = JSON.parse(payload.args)
return {
name: payload.name,
code: payload.code,
language: payload.language,
initiator_type: payload.initiatorType,
json_args: parsedArgs,
active: payload.active
}
}
5 changes: 5 additions & 0 deletions src/services/edge-functions-services/v4/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { listEdgeFunctionsService } from './list-edge-functions-service'
import { listEdgeFunctionsDropdownService } from './list-edge-functions-dropdown-service'
import { loadEdgeFunctionService } from './load-edge-function-service'
import { createEdgeFunctionsService } from './create-edge-functions-service'
import { editEdgeFunctionsService } from './edit-edge-functions-service'
import { deleteEdgeFunctionService } from './delete-edge-function-service'

/**
* @typedef {Object} ExportedServicesType - The type of the exported services
* @property {typeof listEdgeFunctionsService} listEdgeFunctionsService - The listEdgeFunctionsService reference
Expand All @@ -14,5 +17,7 @@ export {
listEdgeFunctionsService,
listEdgeFunctionsDropdownService,
loadEdgeFunctionService,
createEdgeFunctionsService,
editEdgeFunctionsService,
deleteEdgeFunctionService
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,51 @@ export const loadEdgeFunctionService = async ({ id }) => {
return parseHttpResponse(httpResponse)
}

const STATUS_AS_TAG = {
true: {
content: 'Active',
severity: 'success'
},
false: {
content: 'Inactive',
severity: 'danger'
}
}

const LANGUAGE_WITH_ICON = {
javascript: {
content: 'JavaScript',
icon: 'javascript'
},
lua: {
content: 'Lua',
icon: 'lua'
}
}

const adapt = (httpResponse) => {
const { data } = httpResponse.body
const parsedEdgeFunctions = {
const parsedFunction = {
id: data.id,
active: data.active,
language: data.language,
initiatorType: data.initiator_type,
lastEditor: data.last_editor,
referenceCount: data.reference_count,
args: JSON.stringify(data.json_args, null, 2),
name: data.name,
args: JSON.stringify(data.json_args, null, '\t')
code: data.code,
version: data.version || '-',
modified: new Intl.DateTimeFormat('us', { dateStyle: 'full' }).format(
new Date(data.last_modified)
),
statusTag: STATUS_AS_TAG[data.active],
languageIcon: LANGUAGE_WITH_ICON[data.language],
isProprietaryCode: data.is_proprietary_code || false
}

return {
body: parsedEdgeFunctions,
body: parsedFunction,
statusCode: httpResponse.statusCode
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { AxiosHttpClientAdapter } from '@/services/axios/AxiosHttpClientAdapter'
import * as Errors from '@/services/axios/errors'
import { createEdgeFunctionsService } from '@/services/edge-functions-services/v4'
import { describe, expect, it, vi } from 'vitest'

const fixtures = {
edgeFunctionMock: {
name: 'mockFunction',
code: 'function test() { return true }',
language: 'javascript',
initiatorType: 'request',
args: JSON.stringify({ key: 'value' }),
active: true
}
}

const makeSut = () => {
const sut = createEdgeFunctionsService
return { sut }
}

describe('EdgeFunctionsService', () => {
it('should call API with correct params', async () => {
const requestSpy = vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({
statusCode: 202,
body: {
data: {
id: '123456'
}
}
})
const { sut } = makeSut()

await sut(fixtures.edgeFunctionMock)

expect(requestSpy).toHaveBeenCalledWith({
url: expect.any(String),
method: 'POST',
body: {
name: fixtures.edgeFunctionMock.name,
code: fixtures.edgeFunctionMock.code,
language: fixtures.edgeFunctionMock.language,
initiator_type: fixtures.edgeFunctionMock.initiatorType,
json_args: { key: 'value' },
active: fixtures.edgeFunctionMock.active
}
})
})

it('should return feedback and URLs when successfully creating an edge function', async () => {
const functionId = '123456'
vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({
statusCode: 202,
body: {
data: {
id: functionId
}
}
})
const { sut } = makeSut()

const result = await sut(fixtures.edgeFunctionMock)

expect(result).toEqual({
feedback: 'Your edge function has been created',
urlToEditView: `/edge-functions/edit/${functionId}`,
functionId: functionId
})
})

it('should throw internal server error when request fails with 500 status code', async () => {
vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({
statusCode: 500,
body: {
detail: 'Internal server error'
}
})

const { sut } = makeSut()

const apiErrorResponse = sut(fixtures.edgeFunctionMock)
const expectedError = new Errors.InternalServerError().message

expect(apiErrorResponse).rejects.toBe(expectedError)
})

it('should throw parsing api error when request fails', async () => {
const apiErrorMock = {
detail: 'api error message'
}

vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({
statusCode: 400,
body: apiErrorMock
})

const { sut } = makeSut()

const apiErrorResponse = sut(fixtures.edgeFunctionMock)

expect(apiErrorResponse).rejects.toBe('api error message')
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { AxiosHttpClientAdapter } from '@/services/axios/AxiosHttpClientAdapter'
import * as Errors from '@/services/axios/errors'
import { editEdgeFunctionsService } from '@/services/edge-functions-services/v4'
import { describe, expect, it, vi } from 'vitest'

const fixtures = {
edgeFunctionMock: {
id: '123456',
name: 'Test Function',
code: 'function test() { return true; }',
language: 'javascript',
initiatorType: 'event',
args: JSON.stringify({ key: 'value' }),
active: true
}
}

const makeSut = () => {
const sut = editEdgeFunctionsService
return { sut }
}

describe('EdgeFunctionsServices', () => {
it('should call API with correct params', async () => {
const requestSpy = vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({
statusCode: 202
})
const { sut } = makeSut()

await sut(fixtures.edgeFunctionMock)

expect(requestSpy).toHaveBeenCalledWith({
url: `v4/edge_functions/functions/${fixtures.edgeFunctionMock.id}`,
method: 'PATCH',
body: {
name: fixtures.edgeFunctionMock.name,
code: fixtures.edgeFunctionMock.code,
language: fixtures.edgeFunctionMock.language,
initiator_type: fixtures.edgeFunctionMock.initiatorType,
json_args: JSON.parse(fixtures.edgeFunctionMock.args),
active: fixtures.edgeFunctionMock.active
}
})
})

it('should return success message when edge function is updated', async () => {
vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({
statusCode: 202
})
const { sut } = makeSut()

const result = await sut(fixtures.edgeFunctionMock)

expect(result).toBe('Your edge function has been updated')
})

it('should throw internal server error when request fails with 500 status code', async () => {
vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({
statusCode: 500,
body: { detail: 'Internal server error' }
})

const { sut } = makeSut()
const promise = sut(fixtures.edgeFunctionMock)

await expect(promise).rejects.toBe(new Errors.InternalServerError().message)
})

it('should throw API error when request fails with non-500 status code', async () => {
const apiErrorMock = {
detail: 'api error message'
}

vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({
statusCode: 400,
body: apiErrorMock
})

const { sut } = makeSut()
const promise = sut(fixtures.edgeFunctionMock)

await expect(promise).rejects.toBe('api error message')
})
})
Loading
Loading