diff --git a/apps/velo-external-db/test/e2e/app_data.e2e.spec.ts b/apps/velo-external-db/test/e2e/app_data.e2e.spec.ts index 0c883210f..1d56e2e01 100644 --- a/apps/velo-external-db/test/e2e/app_data.e2e.spec.ts +++ b/apps/velo-external-db/test/e2e/app_data.e2e.spec.ts @@ -330,7 +330,7 @@ describe(`Velo External DB Data REST API: ${currentDbImplementationName()}`, () }) describe('error handling', () => { - testIfSupportedOperationsIncludes(supportedOperations, [PrimaryKey])('insert api with duplicate _id should fail with WDE0074, 409', async() => { + testIfSupportedOperationsIncludes(supportedOperations, [PrimaryKey])('insert api with duplicate _id should fail with ITEM_NOT_FOUND, 409', async() => { await schema.givenCollection(ctx.collectionName, [ctx.column], authOwner) await data.givenItems([ctx.item], ctx.collectionName, authAdmin) @@ -363,7 +363,7 @@ describe(`Velo External DB Data REST API: ${currentDbImplementationName()}`, () expect(error).toBeDefined() expect(error.response.status).toEqual(404) expect(error.response.data).toEqual(expect.objectContaining({ - code: 'WDE0025', + errorCode: 'COLLECTION_NOT_FOUND', data: { collectionId: 'nonExistingCollection' } @@ -379,7 +379,7 @@ describe(`Velo External DB Data REST API: ${currentDbImplementationName()}`, () expect(error).toBeDefined() expect(error.response.status).toEqual(400) expect(error.response.data).toEqual(expect.objectContaining({ - code: 'WDE0147', + errorCode: 'FIELD_DOESNT_EXIST', data: { collectionId: ctx.collectionName, propertyName: 'nonExistingColumn' diff --git a/apps/velo-external-db/test/e2e/app_data_hooks.e2e.spec.ts b/apps/velo-external-db/test/e2e/app_data_hooks.e2e.spec.ts index c4efa7aa1..81c23a67a 100644 --- a/apps/velo-external-db/test/e2e/app_data_hooks.e2e.spec.ts +++ b/apps/velo-external-db/test/e2e/app_data_hooks.e2e.spec.ts @@ -525,7 +525,7 @@ describe(`Velo External DB Data Hooks: ${currentDbImplementationName()}`, () => }) await expect(axios.post('/items/remove', hooks.writeRequestBodyWith(ctx.collectionName, [ctx.item]), authOwner)).rejects.toMatchObject( - errorResponseWith('WDE0054', 'message', 409) + errorResponseWith('UNKNOWN_ERROR', 'message', 409) ) }) @@ -540,7 +540,7 @@ describe(`Velo External DB Data Hooks: ${currentDbImplementationName()}`, () => }) await expect(axios.post('/items/remove', hooks.writeRequestBodyWith(ctx.collectionName, [ctx.item]), authOwner)).rejects.toMatchObject( - errorResponseWith('WDE0054', 'message', 500) + errorResponseWith('UNKNOWN_ERROR', 'message', 500) ) }) @@ -554,7 +554,7 @@ describe(`Velo External DB Data Hooks: ${currentDbImplementationName()}`, () => }) await expect(axios.post('/items/remove', hooks.writeRequestBodyWith(ctx.collectionName, [ctx.item]), authOwner)).rejects.toMatchObject( - errorResponseWith('WDE0054', 'message', 500) + errorResponseWith('UNKNOWN_ERROR', 'message', 500) ) }) }) diff --git a/apps/velo-external-db/test/e2e/app_schema_hooks.e2e.spec.ts b/apps/velo-external-db/test/e2e/app_schema_hooks.e2e.spec.ts index a34ade607..727b3745f 100644 --- a/apps/velo-external-db/test/e2e/app_schema_hooks.e2e.spec.ts +++ b/apps/velo-external-db/test/e2e/app_schema_hooks.e2e.spec.ts @@ -258,7 +258,7 @@ describe(`Velo External DB Schema Hooks: ${currentDbImplementationName()}`, () = }) await expect(axiosClient.post('/collections/delete', hooks.collectionWriteRequestBodyWith({ id: ctx.collectionId, fields: [] }), authOwner)).rejects.toMatchObject( - errorResponseWith('WDE0054', 'message', 409) + errorResponseWith('UNKNOWN_ERROR', 'message', 409) ) }) @@ -273,7 +273,7 @@ describe(`Velo External DB Schema Hooks: ${currentDbImplementationName()}`, () = }) await expect(axiosClient.post('/collections/delete', hooks.collectionWriteRequestBodyWith({ id: ctx.collectionId, fields: [] }), authOwner)).rejects.toMatchObject( - errorResponseWith('WDE0054', 'message', 500) + errorResponseWith('UNKNOWN_ERROR', 'message', 500) ) }) @@ -287,7 +287,7 @@ describe(`Velo External DB Schema Hooks: ${currentDbImplementationName()}`, () = }) await expect(axiosClient.post('/collections/delete', hooks.collectionWriteRequestBodyWith({ id: ctx.collectionId, fields: [] }), authOwner)).rejects.toMatchObject( - errorResponseWith('WDE0054', 'message', 500) + errorResponseWith('UNKNOWN_ERROR', 'message', 500) ) }) }) diff --git a/libs/external-db-testkit/src/lib/auth_test_support.ts b/libs/external-db-testkit/src/lib/auth_test_support.ts index 7a7d1104b..860982225 100644 --- a/libs/external-db-testkit/src/lib/auth_test_support.ts +++ b/libs/external-db-testkit/src/lib/auth_test_support.ts @@ -58,7 +58,7 @@ export const authOwnerWithWrongAppId= { transformRequest: axios.defaults -export const errorResponseWith = (code: any, message: string, httpStatusCode: number) => ({ response: { data: { data: { description: expect.stringContaining(message) }, code }, status: httpStatusCode } }) +export const errorResponseWith = (errorCode: any, message: string, httpStatusCode: number) => ({ response: { data: { data: { description: expect.stringContaining(message) }, errorCode }, status: httpStatusCode } }) -export const collectionChangeNotSupportedErrorResponseWith = (fieldsName: string[]) => ({ response: { data: { data: { errors: fieldsName.map(f => ({ fieldKey: f, message: expect.any(String) })) }, code: 'WDE0119' } } }) +export const collectionChangeNotSupportedErrorResponseWith = (fieldsName: string[]) => ({ response: { data: { data: { errors: fieldsName.map(f => ({ fieldKey: f, message: expect.any(String) })) }, errorCode: 'COLLECTION_CHANGE_NOT_SUPPORTED' } } }) diff --git a/libs/velo-external-db-core/src/spi-model/errors.ts b/libs/velo-external-db-core/src/spi-model/errors.ts index ed459f6b5..c6cd3ddae 100644 --- a/libs/velo-external-db-core/src/spi-model/errors.ts +++ b/libs/velo-external-db-core/src/spi-model/errors.ts @@ -1,12 +1,12 @@ class BaseWixError extends Error { collctionName: string httpCode: HttpStatusCode - applicationCode: ApiErrors + errorCode: ErrorCodes - constructor(message: string, httpCode: HttpStatusCode, applicationCode: ApiErrors, collectionName: string) { + constructor(message: string, httpCode: HttpStatusCode, errorCode: ErrorCodes, collectionName: string) { super(message) this.httpCode = httpCode - this.applicationCode = applicationCode + this.errorCode = errorCode this.collctionName = collectionName } } @@ -15,7 +15,7 @@ export class CollectionNotFoundError extends BaseWixError { data: { collectionId: string } constructor(collectionName: string, message: string) { - super(message, HttpStatusCode.NOT_FOUND, ApiErrors.WDE0025, collectionName) + super(message, HttpStatusCode.NOT_FOUND, ErrorCodes.COLLECTION_NOT_FOUND, collectionName) this.data = { collectionId: collectionName } } } @@ -24,7 +24,7 @@ export class CollectionAlreadyExistsError extends BaseWixError { data: { collectionId: string } constructor(collectionName: string, message: string) { - super(message, HttpStatusCode.ALREADY_EXISTS, ApiErrors.WDE0104, collectionName) + super(message, HttpStatusCode.ALREADY_EXISTS, ErrorCodes.COLLECTION_ALREADY_EXISTS, collectionName) this.data = { collectionId: collectionName } } } @@ -33,7 +33,7 @@ export class ItemNotFoundError extends BaseWixError { data: { itemId: string } constructor(collectionName: string, itemId: string, message: string) { - super(message, HttpStatusCode.NOT_FOUND, ApiErrors.WDE0073, collectionName) + super(message, HttpStatusCode.NOT_FOUND, ErrorCodes.ITEM_NOT_FOUND, collectionName) this.data = { itemId } } } @@ -42,7 +42,7 @@ export class ItemAlreadyExistsError extends BaseWixError { data: { itemId: string } constructor(collectionName: string, itemId: string, message: string) { - super(message, HttpStatusCode.ALREADY_EXISTS, ApiErrors.WDE0074, collectionName) + super(message, HttpStatusCode.ALREADY_EXISTS, ErrorCodes.ITEM_ALREADY_EXISTS, collectionName) this.data = { itemId } } } @@ -53,7 +53,7 @@ export class ReferenceNotFoundError extends BaseWixError { data: { referringItemId: string, referencedItemId: string } constructor(message: string, collectionName: string, referringItemId: string, referencedItemId: string) { - super(message, HttpStatusCode.NOT_FOUND, ApiErrors.WDE0029, collectionName) + super(message, HttpStatusCode.NOT_FOUND, ErrorCodes.REFERENCE_NOT_FOUND, collectionName) this.referringItemId = referringItemId this.referencedItemId = referencedItemId this.data = { referringItemId, referencedItemId } @@ -66,7 +66,7 @@ export class ReferenceAlreadyExistsError extends BaseWixError { data: { referringItemId: string, referencedItemId: string } constructor(message: string, collectionName: string, referringItemId: string, referencedItemId: string) { - super(message, HttpStatusCode.ALREADY_EXISTS, ApiErrors.WDE0029, collectionName) + super(message, HttpStatusCode.ALREADY_EXISTS, ErrorCodes.REFERENCE_ALREADY_EXISTS, collectionName) this.referringItemId = referringItemId this.referencedItemId = referencedItemId this.data = { referringItemId, referencedItemId } @@ -84,7 +84,7 @@ export class ValidationError extends BaseWixError { data: { violations: ValidationViolation[] } constructor(message: string, collectionName: string, fieldPath: string, rejectedValue: string) { - super(message, HttpStatusCode.INVALID_ARGUMENT, ApiErrors.WDE0075, collectionName) + super(message, HttpStatusCode.INVALID_ARGUMENT, ErrorCodes.VALIDATION_ERROR, collectionName) this.violations = [{ fieldPath, rejectedValue, message }] this.data = { violations: this.violations } } @@ -100,7 +100,7 @@ export class CollectionChangeNotSupportedError extends BaseWixError { data: { errors: CollectionChangeNotSupportedErrorItem[] } constructor(collectionName: string, fieldKey: string, message: string) { - super(message, HttpStatusCode.INVALID_ARGUMENT, ApiErrors.WDE0119, collectionName) + super(message, HttpStatusCode.INVALID_ARGUMENT, ErrorCodes.COLLECTION_CHANGE_NOT_SUPPORTED, collectionName) this.errors = [{ fieldKey, message }] this.data = { errors: this.errors } } @@ -109,17 +109,16 @@ export class CollectionChangeNotSupportedError extends BaseWixError { export class UnknownError extends BaseWixError { data: { description: string } constructor(message: string, httpCode: number = HttpStatusCode.INTERNAL) { - super(message, httpCode, ApiErrors.WDE0054, '') + super(message, httpCode, ErrorCodes.UNKNOWN_ERROR, '') this.data = { description: message } } } - -export class InvalidPropertyError extends BaseWixError { +export class FieldDoesNotExist extends BaseWixError { data: { collectionId: string, propertyName: string } constructor(collectionName: string, propertyName: string, message: string) { - super(message, HttpStatusCode.INVALID_ARGUMENT, ApiErrors.WDE0147, collectionName) + super(message, HttpStatusCode.INVALID_ARGUMENT, ErrorCodes.FIELD_DOESNT_EXIST, collectionName) this.data = { collectionId: collectionName, propertyName } } } @@ -128,7 +127,7 @@ export class InvalidPropertyError extends BaseWixError { export class UnauthorizedError extends BaseWixError { data: { description: string } constructor(message: string) { - super(message, HttpStatusCode.UNAUTHENTICATED, ApiErrors.WDE0027, '') + super(message, HttpStatusCode.UNAUTHENTICATED, ErrorCodes.UNAUTHORIZED, '') this.data = { description: message } } } @@ -137,7 +136,7 @@ export class FieldAlreadyExistsError extends BaseWixError { data: { collectionId: string, fieldName: string } constructor(collectionName: string, fieldName: string, message: string) { - super(message, HttpStatusCode.ALREADY_EXISTS, ApiErrors.WDE0123, collectionName) + super(message, HttpStatusCode.ALREADY_EXISTS, ErrorCodes.FIELD_ALREADY_EXISTS, collectionName) this.data = { collectionId: collectionName, fieldName } } } @@ -146,7 +145,7 @@ export class UnsupportedSchemaOperation extends BaseWixError { data: { collectionId: string, operation: string } constructor(collectionName: string, operation: string, message: string) { - super(message, HttpStatusCode.INVALID_ARGUMENT, ApiErrors.WDE0119, collectionName) + super(message, HttpStatusCode.INVALID_ARGUMENT, ErrorCodes.UNSUPPORTED_OPERATION, collectionName) this.data = { collectionId: collectionName, operation } } } @@ -263,3 +262,20 @@ export enum HttpStatusCode { // DATA_LOSS = 14; // 500 // UNIMPLEMENTED = 15; // 501 } + + enum ErrorCodes { + ITEM_ALREADY_EXISTS = 'ITEM_ALREADY_EXISTS', + ITEM_NOT_FOUND = 'ITEM_NOT_FOUND', + COLLECTION_ALREADY_EXISTS = 'COLLECTION_ALREADY_EXISTS', + COLLECTION_NOT_FOUND = 'COLLECTION_NOT_FOUND', + REFERENCE_ALREADY_EXISTS = 'REFERENCE_ALREADY_EXISTS', + REFERENCE_NOT_FOUND = 'REFERENCE_NOT_FOUND', + VALIDATION_ERROR = 'VALIDATION_ERROR', + COLLECTION_CHANGE_NOT_SUPPORTED = 'COLLECTION_CHANGE_NOT_SUPPORTED', + // These errors are not in the official SPI + FIELD_DOESNT_EXIST = 'FIELD_DOESNT_EXIST', + FIELD_ALREADY_EXISTS = 'FIELD_ALREADY_EXISTS', + UNAUTHORIZED = 'UNAUTHORIZED', + UNSUPPORTED_OPERATION = 'UNSUPPORTED_OPERATION', + UNKNOWN_ERROR = 'UNKNOWN_ERROR' + } diff --git a/libs/velo-external-db-core/src/web/domain-to-spi-error-translator.ts b/libs/velo-external-db-core/src/web/domain-to-spi-error-translator.ts index 3213be2e7..6897527a8 100644 --- a/libs/velo-external-db-core/src/web/domain-to-spi-error-translator.ts +++ b/libs/velo-external-db-core/src/web/domain-to-spi-error-translator.ts @@ -1,6 +1,6 @@ import { errors as domainErrors } from '@wix-velo/velo-external-db-commons' import { ItemAlreadyExistsError, CollectionNotFoundError, ItemNotFoundError, CollectionAlreadyExistsError, CollectionChangeNotSupportedError, - UnknownError, InvalidPropertyError, UnauthorizedError, FieldAlreadyExistsError, UnsupportedSchemaOperation } from '../spi-model/errors' + UnknownError, FieldDoesNotExist, UnauthorizedError, FieldAlreadyExistsError, UnsupportedSchemaOperation } from '../spi-model/errors' export const domainToSpiErrorTranslator = (err: any) => { switch(err.constructor) { @@ -18,7 +18,7 @@ export const domainToSpiErrorTranslator = (err: any) => { case domainErrors.FieldDoesNotExist: const fieldDoesNotExist = err as domainErrors.FieldDoesNotExist - return new InvalidPropertyError(fieldDoesNotExist.collectionName, fieldDoesNotExist.propertyName, fieldDoesNotExist.message) + return new FieldDoesNotExist(fieldDoesNotExist.collectionName, fieldDoesNotExist.propertyName, fieldDoesNotExist.message) case domainErrors.UnsupportedSchemaOperation: const unsupportedSchemaOperation = err as domainErrors.UnsupportedSchemaOperation diff --git a/libs/velo-external-db-core/src/web/error-middleware.ts b/libs/velo-external-db-core/src/web/error-middleware.ts index 620f79c8d..d8fc16bb7 100644 --- a/libs/velo-external-db-core/src/web/error-middleware.ts +++ b/libs/velo-external-db-core/src/web/error-middleware.ts @@ -9,6 +9,6 @@ export const errorMiddleware = (err: any, _req: any, res: Response, _next?: Next const error = domainToSpiErrorTranslator(err) res.status(error.httpCode).send({ data: error.data, - code: error.applicationCode + errorCode: error.errorCode, }) }