From 557f3b0569ff2f1cac8c9e2353161efae7930352 Mon Sep 17 00:00:00 2001 From: Ryan Smith <0ryansmith1994@gmail.com> Date: Fri, 16 Mar 2018 11:14:28 +0000 Subject: [PATCH 1/3] feat: Simplifies error catching. --- package-lock.json | 14 +++++++++++ package.json | 4 ++- src/FacadeConfig.ts | 4 +-- src/FactoryConfig.ts | 4 +-- src/factory.ts | 4 +-- src/functions/countEntities.ts | 14 ++++++----- src/functions/createEntity.ts | 16 ++++++------ src/functions/getEntities.ts | 42 ++++++++++++++++--------------- src/functions/getEntity.ts | 16 ++++++------ src/functions/patchEntities.ts | 18 ++++++++------ src/functions/removeEntities.ts | 14 ++++++----- src/functions/removeEntity.ts | 16 ++++++------ src/functions/replaceEntity.ts | 18 ++++++++------ src/utils/ErrorCatcher.ts | 7 ------ src/utils/ErrorHandler.ts | 12 +++++++++ src/utils/catchErrors.ts | 29 ---------------------- src/utils/handleError.ts | 44 +++++++++++++++++++++++++++++++++ src/utils/handleTransaction.ts | 26 +++++++++++++++++++ 18 files changed, 190 insertions(+), 112 deletions(-) delete mode 100644 src/utils/ErrorCatcher.ts create mode 100644 src/utils/ErrorHandler.ts delete mode 100644 src/utils/catchErrors.ts create mode 100644 src/utils/handleError.ts create mode 100644 src/utils/handleTransaction.ts diff --git a/package-lock.json b/package-lock.json index 8cf4a443..c518c2db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -266,6 +266,15 @@ "@types/node": "9.4.7" } }, + "@types/uuid": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.3.tgz", + "integrity": "sha512-5fRLCYhLtDb3hMWqQyH10qtF+Ud2JnNCXTCZ+9ktNdCcgslcuXkDTkFcJNk++MT29yDntDnlF1+jD+uVGumsbw==", + "dev": true, + "requires": { + "@types/node": "9.4.7" + } + }, "JSONStream": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.2.tgz", @@ -7640,6 +7649,11 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", "dev": true }, + "uuid": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" + }, "validate-npm-package-license": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", diff --git a/package.json b/package.json index 6cb78e5a..9812f394 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ }, "dependencies": { "@js-entity-repos/core": "^6.0.2", - "http-status-codes": "^1.3.0" + "http-status-codes": "^1.3.0", + "uuid": "^3.2.1" }, "devDependencies": { "@ht2-labs/semantic-release": "1.0.31", @@ -37,6 +38,7 @@ "@types/express": "4.11.1", "@types/mocha": "2.2.48", "@types/source-map-support": "0.4.0", + "@types/uuid": "3.4.3", "assert-rejects": "0.1.1", "axios": "0.18.0", "dotenv": "5.0.1", diff --git a/src/FacadeConfig.ts b/src/FacadeConfig.ts index e1f7d41e..e8e83044 100644 --- a/src/FacadeConfig.ts +++ b/src/FacadeConfig.ts @@ -1,11 +1,11 @@ import Facade from '@js-entity-repos/core/dist/Facade'; import Entity from '@js-entity-repos/core/dist/types/Entity'; import Filter from '@js-entity-repos/core/dist/types/Filter'; -import ErrorCatcher from './utils/ErrorCatcher'; +import ErrorHandler from './utils/ErrorHandler'; export default interface FacadeConfig { readonly constructFilter: (filter: Filter) => any; readonly service: Facade; - readonly errorCatcher: ErrorCatcher; + readonly handleError: ErrorHandler; readonly defaultPaginationLimit: number; } diff --git a/src/FactoryConfig.ts b/src/FactoryConfig.ts index f2dfb569..c25e5b17 100644 --- a/src/FactoryConfig.ts +++ b/src/FactoryConfig.ts @@ -1,11 +1,11 @@ import Facade from '@js-entity-repos/core/dist/Facade'; import Entity from '@js-entity-repos/core/dist/types/Entity'; import { Filter } from '@js-entity-repos/core/dist/types/Filter'; -import ErrorCatcher from './utils/ErrorCatcher'; +import ErrorHandler from './utils/ErrorHandler'; export default interface FactoryConfig { readonly constructFilter?: (filter: Filter) => any; readonly service: Facade; - readonly errorCatcher?: ErrorCatcher; + readonly handleError?: ErrorHandler; readonly defaultPaginationLimit?: number; } diff --git a/src/factory.ts b/src/factory.ts index 7b397947..4f3c1359 100644 --- a/src/factory.ts +++ b/src/factory.ts @@ -11,13 +11,13 @@ import patchEntities from './functions/patchEntities'; import removeEntities from './functions/removeEntities'; import removeEntity from './functions/removeEntity'; import replaceEntity from './functions/replaceEntity'; -import catchErrors from './utils/catchErrors'; +import handleError from './utils/handleError'; export default (factoryConfig: FactoryConfig): Router => { const facadeConfig: FacadeConfig = { constructFilter: (filter) => filter, defaultPaginationLimit: 10, - errorCatcher: catchErrors, + handleError, ...factoryConfig, }; const router = Router(); diff --git a/src/functions/countEntities.ts b/src/functions/countEntities.ts index f75e697e..178dafb6 100644 --- a/src/functions/countEntities.ts +++ b/src/functions/countEntities.ts @@ -2,14 +2,16 @@ import Entity from '@js-entity-repos/core/dist/types/Entity'; import { Request, Response } from 'express'; import { OK } from 'http-status-codes'; import FacadeConfig from '../FacadeConfig'; -import catchErrors from '../utils/catchErrors'; import getJsonQueryParam from '../utils/getJsonQueryParam'; +import handleTransaction from '../utils/handleTransaction'; export default (config: FacadeConfig) => { - return catchErrors(async (req: Request, res: Response) => { - const { count } = await config.service.countEntities({ - filter: config.constructFilter(getJsonQueryParam(req.query, 'filter')), + return async (req: Request, res: Response) => { + await handleTransaction({ config, req, res }, async () => { + const { count } = await config.service.countEntities({ + filter: config.constructFilter(getJsonQueryParam(req.query, 'filter')), + }); + res.status(OK).json(count); }); - res.status(OK).json(count); - }); + }; }; diff --git a/src/functions/createEntity.ts b/src/functions/createEntity.ts index 61d0efa3..12187987 100644 --- a/src/functions/createEntity.ts +++ b/src/functions/createEntity.ts @@ -2,14 +2,16 @@ import Entity from '@js-entity-repos/core/dist/types/Entity'; import { Request, Response } from 'express'; import { OK } from 'http-status-codes'; import FacadeConfig from '../FacadeConfig'; -import catchErrors from '../utils/catchErrors'; +import handleTransaction from '../utils/handleTransaction'; export default (config: FacadeConfig) => { - return catchErrors(async (req: Request, res: Response) => { - const { entity } = await config.service.createEntity({ - entity: req.body, - id: req.body.id, + return async (req: Request, res: Response) => { + await handleTransaction({ config, req, res }, async () => { + const { entity } = await config.service.createEntity({ + entity: req.body, + id: req.body.id, + }); + res.status(OK).json(entity); }); - res.status(OK).json(entity); - }); + }; }; diff --git a/src/functions/getEntities.ts b/src/functions/getEntities.ts index d40202e3..1994ce86 100644 --- a/src/functions/getEntities.ts +++ b/src/functions/getEntities.ts @@ -2,29 +2,31 @@ import Entity from '@js-entity-repos/core/dist/types/Entity'; import { Request, Response } from 'express'; import { OK } from 'http-status-codes'; import FacadeConfig from '../FacadeConfig'; -import catchErrors from '../utils/catchErrors'; import getJsonQueryParam from '../utils/getJsonQueryParam'; import getNumberQueryParam from '../utils/getNumberQueryParam'; +import handleTransaction from '../utils/handleTransaction'; export default (config: FacadeConfig) => { - return catchErrors(async (req: Request, res: Response) => { - const limit = getNumberQueryParam(req.query, 'limit', config.defaultPaginationLimit); - const result = await config.service.getEntities({ - filter: config.constructFilter(getJsonQueryParam(req.query, 'filter')), - pagination: { - cursor: req.query.cursor, - forward: req.query.forward === 'true', - limit, - }, - sort: getJsonQueryParam(req.query, 'sort'), + return async (req: Request, res: Response) => { + await handleTransaction({ config, req, res }, async () => { + const limit = getNumberQueryParam(req.query, 'limit', config.defaultPaginationLimit); + const result = await config.service.getEntities({ + filter: config.constructFilter(getJsonQueryParam(req.query, 'filter')), + pagination: { + cursor: req.query.cursor, + forward: req.query.forward === 'true', + limit, + }, + sort: getJsonQueryParam(req.query, 'sort'), + }); + res.status(OK); + if (result.nextCursor !== undefined) { + res.setHeader('x-entities-next-cursor', result.nextCursor); + } + if (result.previousCursor !== undefined) { + res.setHeader('x-entities-previous-cursor', result.previousCursor); + } + res.json(result.entities); }); - res.status(OK); - if (result.nextCursor !== undefined) { - res.setHeader('x-entities-next-cursor', result.nextCursor); - } - if (result.previousCursor !== undefined) { - res.setHeader('x-entities-previous-cursor', result.previousCursor); - } - res.json(result.entities); - }); + }; }; diff --git a/src/functions/getEntity.ts b/src/functions/getEntity.ts index f1aed8a8..9dcf44db 100644 --- a/src/functions/getEntity.ts +++ b/src/functions/getEntity.ts @@ -2,15 +2,17 @@ import Entity from '@js-entity-repos/core/dist/types/Entity'; import { Request, Response } from 'express'; import { OK } from 'http-status-codes'; import FacadeConfig from '../FacadeConfig'; -import catchErrors from '../utils/catchErrors'; import getJsonQueryParam from '../utils/getJsonQueryParam'; +import handleTransaction from '../utils/handleTransaction'; export default (config: FacadeConfig) => { - return catchErrors(async (req: Request, res: Response) => { - const { entity } = await config.service.getEntity({ - filter: config.constructFilter(getJsonQueryParam(req.query, 'filter')), - id: req.params.id, + return async (req: Request, res: Response) => { + await handleTransaction({ config, req, res }, async () => { + const { entity } = await config.service.getEntity({ + filter: config.constructFilter(getJsonQueryParam(req.query, 'filter')), + id: req.params.id, + }); + res.status(OK).json(entity); }); - res.status(OK).json(entity); - }); + }; }; diff --git a/src/functions/patchEntities.ts b/src/functions/patchEntities.ts index e11e40dd..76f077d8 100644 --- a/src/functions/patchEntities.ts +++ b/src/functions/patchEntities.ts @@ -2,16 +2,18 @@ import Entity from '@js-entity-repos/core/dist/types/Entity'; import { Request, Response } from 'express'; import { OK } from 'http-status-codes'; import FacadeConfig from '../FacadeConfig'; -import catchErrors from '../utils/catchErrors'; import getJsonQueryParam from '../utils/getJsonQueryParam'; +import handleTransaction from '../utils/handleTransaction'; export default (config: FacadeConfig) => { - return catchErrors(async (req: Request, res: Response) => { - const { entity } = await config.service.patchEntity({ - filter: config.constructFilter(getJsonQueryParam(req.query, 'filter')), - id: req.params.id, - patch: req.body, + return async (req: Request, res: Response) => { + await handleTransaction({ config, req, res }, async () => { + const { entity } = await config.service.patchEntity({ + filter: config.constructFilter(getJsonQueryParam(req.query, 'filter')), + id: req.params.id, + patch: req.body, + }); + res.status(OK).json(entity); }); - res.status(OK).json(entity); - }); + }; }; diff --git a/src/functions/removeEntities.ts b/src/functions/removeEntities.ts index 7a0952ae..f27b80f8 100644 --- a/src/functions/removeEntities.ts +++ b/src/functions/removeEntities.ts @@ -2,14 +2,16 @@ import Entity from '@js-entity-repos/core/dist/types/Entity'; import { Request, Response } from 'express'; import { NO_CONTENT } from 'http-status-codes'; import FacadeConfig from '../FacadeConfig'; -import catchErrors from '../utils/catchErrors'; import getJsonQueryParam from '../utils/getJsonQueryParam'; +import handleTransaction from '../utils/handleTransaction'; export default (config: FacadeConfig) => { - return catchErrors(async (req: Request, res: Response) => { - await config.service.removeEntities({ - filter: config.constructFilter(getJsonQueryParam(req.query, 'filter')), + return async (req: Request, res: Response) => { + await handleTransaction({ config, req, res }, async () => { + await config.service.removeEntities({ + filter: config.constructFilter(getJsonQueryParam(req.query, 'filter')), + }); + res.status(NO_CONTENT).send(); }); - res.status(NO_CONTENT).send(); - }); + }; }; diff --git a/src/functions/removeEntity.ts b/src/functions/removeEntity.ts index c9fb7b76..43ef400f 100644 --- a/src/functions/removeEntity.ts +++ b/src/functions/removeEntity.ts @@ -2,15 +2,17 @@ import Entity from '@js-entity-repos/core/dist/types/Entity'; import { Request, Response } from 'express'; import { NO_CONTENT } from 'http-status-codes'; import FacadeConfig from '../FacadeConfig'; -import catchErrors from '../utils/catchErrors'; import getJsonQueryParam from '../utils/getJsonQueryParam'; +import handleTransaction from '../utils/handleTransaction'; export default (config: FacadeConfig) => { - return catchErrors(async (req: Request, res: Response) => { - await config.service.removeEntity({ - filter: config.constructFilter(getJsonQueryParam(req.query, 'filter')), - id: req.params.id, + return async (req: Request, res: Response) => { + await handleTransaction({ config, req, res }, async () => { + await config.service.removeEntity({ + filter: config.constructFilter(getJsonQueryParam(req.query, 'filter')), + id: req.params.id, + }); + res.status(NO_CONTENT).send(); }); - res.status(NO_CONTENT).send(); - }); + }; }; diff --git a/src/functions/replaceEntity.ts b/src/functions/replaceEntity.ts index f7d5ee38..95c322ae 100644 --- a/src/functions/replaceEntity.ts +++ b/src/functions/replaceEntity.ts @@ -2,16 +2,18 @@ import Entity from '@js-entity-repos/core/dist/types/Entity'; import { Request, Response } from 'express'; import { OK } from 'http-status-codes'; import FacadeConfig from '../FacadeConfig'; -import catchErrors from '../utils/catchErrors'; import getJsonQueryParam from '../utils/getJsonQueryParam'; +import handleTransaction from '../utils/handleTransaction'; export default (config: FacadeConfig) => { - return catchErrors(async (req: Request, res: Response) => { - const { entity } = await config.service.replaceEntity({ - entity: req.body, - filter: config.constructFilter(getJsonQueryParam(req.query, 'filter')), - id: req.params.id, + return async (req: Request, res: Response) => { + await handleTransaction({ config, req, res }, async () => { + const { entity } = await config.service.replaceEntity({ + entity: req.body, + filter: config.constructFilter(getJsonQueryParam(req.query, 'filter')), + id: req.params.id, + }); + res.status(OK).json(entity); }); - res.status(OK).json(entity); - }); + }; }; diff --git a/src/utils/ErrorCatcher.ts b/src/utils/ErrorCatcher.ts deleted file mode 100644 index f0fa55a5..00000000 --- a/src/utils/ErrorCatcher.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Request, Response } from 'express'; - -export type Handler = (req: Request, res: Response) => Promise; - -type ErrorCatcher = (handler: Handler) => (req: Request, res: Response) => void; - -export default ErrorCatcher; diff --git a/src/utils/ErrorHandler.ts b/src/utils/ErrorHandler.ts new file mode 100644 index 00000000..07819a55 --- /dev/null +++ b/src/utils/ErrorHandler.ts @@ -0,0 +1,12 @@ +import { Request, Response } from 'express'; + +export interface Opts { + readonly req: Request; + readonly res: Response; + readonly err: any; + readonly transactionId: string; +} + +type ErrorHandler = (opts: Opts) => void; + +export default ErrorHandler; diff --git a/src/utils/catchErrors.ts b/src/utils/catchErrors.ts deleted file mode 100644 index c15dd6e9..00000000 --- a/src/utils/catchErrors.ts +++ /dev/null @@ -1,29 +0,0 @@ -import ConflictingEntityError from '@js-entity-repos/core/dist/errors/ConflictingEntityError'; -import MissingEntityError from '@js-entity-repos/core/dist/errors/MissingEntityError'; -import { BAD_REQUEST, CONFLICT, INTERNAL_SERVER_ERROR, NOT_FOUND } from 'http-status-codes'; -import ErrorCatcher from './ErrorCatcher'; -import JsonError from './JsonError'; -import NumberError from './NumberError'; - -const errorCatcher: ErrorCatcher = (handler) => { - return (req, res) => { - handler(req, res).catch((err) => { - if (err instanceof ConflictingEntityError) { - return res.status(CONFLICT).send(); - } - if (err instanceof MissingEntityError) { - return res.status(NOT_FOUND).send(); - } - if (err instanceof JsonError) { - return res.status(BAD_REQUEST).send(); - } - if (err instanceof NumberError) { - return res.status(BAD_REQUEST).send(); - } - /* istanbul ignore next */ - return res.status(INTERNAL_SERVER_ERROR).send(); - }); - }; -}; - -export default errorCatcher; diff --git a/src/utils/handleError.ts b/src/utils/handleError.ts new file mode 100644 index 00000000..01f85d17 --- /dev/null +++ b/src/utils/handleError.ts @@ -0,0 +1,44 @@ +import ConflictingEntityError from '@js-entity-repos/core/dist/errors/ConflictingEntityError'; +import MissingEntityError from '@js-entity-repos/core/dist/errors/MissingEntityError'; +import { BAD_REQUEST, CONFLICT, INTERNAL_SERVER_ERROR, NOT_FOUND } from 'http-status-codes'; +import ErrorHandler from './ErrorHandler'; +import JsonError from './JsonError'; +import NumberError from './NumberError'; + +const handleError: ErrorHandler = ({ res, err, transactionId }) => { + const sendErrorResponse = (statusCode: number, errorData: object) => { + const body = { + ...errorData, + transactionId, + }; + res.status(statusCode).json(body); + }; + if (err instanceof ConflictingEntityError) { + return sendErrorResponse(CONFLICT, { + entityId: err.entityId, + entityName: err.entityName, + }); + } + if (err instanceof MissingEntityError) { + return sendErrorResponse(NOT_FOUND, { + entityId: err.entityId, + entityName: err.entityName, + }); + } + if (err instanceof JsonError) { + return sendErrorResponse(BAD_REQUEST, { + data: err.data, + path: err.path, + }); + } + if (err instanceof NumberError) { + return sendErrorResponse(BAD_REQUEST, { + data: err.data, + path: err.path, + }); + } + /* istanbul ignore next */ + return sendErrorResponse(INTERNAL_SERVER_ERROR, {}); +}; + +export default handleError; diff --git a/src/utils/handleTransaction.ts b/src/utils/handleTransaction.ts new file mode 100644 index 00000000..c0a50b66 --- /dev/null +++ b/src/utils/handleTransaction.ts @@ -0,0 +1,26 @@ +import Entity from '@js-entity-repos/core/dist/types/Entity'; +import { Request } from 'express'; +import { Response } from 'express-serve-static-core'; +import { v4 as uuid } from 'uuid'; +import FacadeConfig from '../FacadeConfig'; + +export interface Opts { + readonly config: FacadeConfig; + readonly req: Request; + readonly res: Response; +} + +export interface HandlerOpts { + readonly transactionId: string; +} + +export type Handler = (opts: HandlerOpts) => Promise; + +export default async ({ config, req, res }: Opts, handler: Handler) => { + const transactionId = uuid(); + try { + await handler({ transactionId }); + } catch (err) { + config.handleError({ req, res, err, transactionId }); + } +}; From f74596fc06b5a3cde111af2536e5efa293462244 Mon Sep 17 00:00:00 2001 From: Ryan Smith <0ryansmith1994@gmail.com> Date: Fri, 16 Mar 2018 11:21:11 +0000 Subject: [PATCH 2/3] ci(tslint): Fixes linting errors. --- src/utils/handleError.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/utils/handleError.ts b/src/utils/handleError.ts index 01f85d17..8526a823 100644 --- a/src/utils/handleError.ts +++ b/src/utils/handleError.ts @@ -14,31 +14,36 @@ const handleError: ErrorHandler = ({ res, err, transactionId }) => { res.status(statusCode).json(body); }; if (err instanceof ConflictingEntityError) { - return sendErrorResponse(CONFLICT, { + sendErrorResponse(CONFLICT, { entityId: err.entityId, entityName: err.entityName, }); + return; } if (err instanceof MissingEntityError) { - return sendErrorResponse(NOT_FOUND, { + sendErrorResponse(NOT_FOUND, { entityId: err.entityId, entityName: err.entityName, }); + return; } if (err instanceof JsonError) { - return sendErrorResponse(BAD_REQUEST, { + sendErrorResponse(BAD_REQUEST, { data: err.data, path: err.path, }); + return; } if (err instanceof NumberError) { - return sendErrorResponse(BAD_REQUEST, { + sendErrorResponse(BAD_REQUEST, { data: err.data, path: err.path, }); + return; } /* istanbul ignore next */ - return sendErrorResponse(INTERNAL_SERVER_ERROR, {}); + sendErrorResponse(INTERNAL_SERVER_ERROR, {}); + return; }; export default handleError; From db0e1b438c512b584cba16d09155ed92df456c69 Mon Sep 17 00:00:00 2001 From: Ryan Smith <0ryansmith1994@gmail.com> Date: Fri, 16 Mar 2018 11:38:00 +0000 Subject: [PATCH 3/3] feat: Adds handleTransaction to FactoryConfig. --- readme.md | 17 +++++++++++------ src/FacadeConfig.ts | 4 ++-- src/FactoryConfig.ts | 4 ++-- src/factory.ts | 4 ++-- src/functions/countEntities.ts | 3 +-- src/functions/createEntity.ts | 3 +-- src/functions/getEntities.ts | 3 +-- src/functions/getEntity.ts | 3 +-- src/functions/patchEntities.ts | 3 +-- src/functions/removeEntities.ts | 3 +-- src/functions/removeEntity.ts | 3 +-- src/functions/replaceEntity.ts | 3 +-- src/utils/TransactionHandler.ts | 17 +++++++++++++++++ src/utils/handleError.ts | 6 ++++-- src/utils/handleTransaction.ts | 24 ++++++------------------ 15 files changed, 52 insertions(+), 48 deletions(-) create mode 100644 src/utils/TransactionHandler.ts diff --git a/readme.md b/readme.md index 434d2a95..2550043c 100644 --- a/readme.md +++ b/readme.md @@ -33,12 +33,17 @@ const todosFacade = factory({ }, // Optional property. defaultPaginationLimit: 10, - // Optional property that catches errors from handlers. - errorCatcher: (handler) => (req, res) => { - handler(req, res).catch((err) => { - res.status(500).send(); - }); - }, + // Optional property to handle transactions. + handleTransaction: async ({ req, res }, handler) => { + // The transactionId allow items found in logs to be matched with responses to users. + const transactionId = uuid(); + try { + await handler({ transactionId }); + } catch (err) { + console.error({ err, req, res, transactionId}) + res.status(500).send(transactionId); + } + }; service, }); ``` diff --git a/src/FacadeConfig.ts b/src/FacadeConfig.ts index e8e83044..892d90be 100644 --- a/src/FacadeConfig.ts +++ b/src/FacadeConfig.ts @@ -1,11 +1,11 @@ import Facade from '@js-entity-repos/core/dist/Facade'; import Entity from '@js-entity-repos/core/dist/types/Entity'; import Filter from '@js-entity-repos/core/dist/types/Filter'; -import ErrorHandler from './utils/ErrorHandler'; +import TransactionHandler from './utils/TransactionHandler'; export default interface FacadeConfig { readonly constructFilter: (filter: Filter) => any; readonly service: Facade; - readonly handleError: ErrorHandler; + readonly handleTransaction: TransactionHandler; readonly defaultPaginationLimit: number; } diff --git a/src/FactoryConfig.ts b/src/FactoryConfig.ts index c25e5b17..2aae9cc6 100644 --- a/src/FactoryConfig.ts +++ b/src/FactoryConfig.ts @@ -1,11 +1,11 @@ import Facade from '@js-entity-repos/core/dist/Facade'; import Entity from '@js-entity-repos/core/dist/types/Entity'; import { Filter } from '@js-entity-repos/core/dist/types/Filter'; -import ErrorHandler from './utils/ErrorHandler'; +import TransactionHandler from './utils/TransactionHandler'; export default interface FactoryConfig { readonly constructFilter?: (filter: Filter) => any; readonly service: Facade; - readonly handleError?: ErrorHandler; + readonly handleTransaction?: TransactionHandler; readonly defaultPaginationLimit?: number; } diff --git a/src/factory.ts b/src/factory.ts index 4f3c1359..5f867a0b 100644 --- a/src/factory.ts +++ b/src/factory.ts @@ -11,13 +11,13 @@ import patchEntities from './functions/patchEntities'; import removeEntities from './functions/removeEntities'; import removeEntity from './functions/removeEntity'; import replaceEntity from './functions/replaceEntity'; -import handleError from './utils/handleError'; +import handleTransaction from './utils/handleTransaction'; export default (factoryConfig: FactoryConfig): Router => { const facadeConfig: FacadeConfig = { constructFilter: (filter) => filter, defaultPaginationLimit: 10, - handleError, + handleTransaction, ...factoryConfig, }; const router = Router(); diff --git a/src/functions/countEntities.ts b/src/functions/countEntities.ts index 178dafb6..5500fe6f 100644 --- a/src/functions/countEntities.ts +++ b/src/functions/countEntities.ts @@ -3,11 +3,10 @@ import { Request, Response } from 'express'; import { OK } from 'http-status-codes'; import FacadeConfig from '../FacadeConfig'; import getJsonQueryParam from '../utils/getJsonQueryParam'; -import handleTransaction from '../utils/handleTransaction'; export default (config: FacadeConfig) => { return async (req: Request, res: Response) => { - await handleTransaction({ config, req, res }, async () => { + await config.handleTransaction({ req, res }, async () => { const { count } = await config.service.countEntities({ filter: config.constructFilter(getJsonQueryParam(req.query, 'filter')), }); diff --git a/src/functions/createEntity.ts b/src/functions/createEntity.ts index 12187987..f57eece1 100644 --- a/src/functions/createEntity.ts +++ b/src/functions/createEntity.ts @@ -2,11 +2,10 @@ import Entity from '@js-entity-repos/core/dist/types/Entity'; import { Request, Response } from 'express'; import { OK } from 'http-status-codes'; import FacadeConfig from '../FacadeConfig'; -import handleTransaction from '../utils/handleTransaction'; export default (config: FacadeConfig) => { return async (req: Request, res: Response) => { - await handleTransaction({ config, req, res }, async () => { + await config.handleTransaction({ req, res }, async () => { const { entity } = await config.service.createEntity({ entity: req.body, id: req.body.id, diff --git a/src/functions/getEntities.ts b/src/functions/getEntities.ts index 1994ce86..98718cd7 100644 --- a/src/functions/getEntities.ts +++ b/src/functions/getEntities.ts @@ -4,11 +4,10 @@ import { OK } from 'http-status-codes'; import FacadeConfig from '../FacadeConfig'; import getJsonQueryParam from '../utils/getJsonQueryParam'; import getNumberQueryParam from '../utils/getNumberQueryParam'; -import handleTransaction from '../utils/handleTransaction'; export default (config: FacadeConfig) => { return async (req: Request, res: Response) => { - await handleTransaction({ config, req, res }, async () => { + await config.handleTransaction({ req, res }, async () => { const limit = getNumberQueryParam(req.query, 'limit', config.defaultPaginationLimit); const result = await config.service.getEntities({ filter: config.constructFilter(getJsonQueryParam(req.query, 'filter')), diff --git a/src/functions/getEntity.ts b/src/functions/getEntity.ts index 9dcf44db..0cc13324 100644 --- a/src/functions/getEntity.ts +++ b/src/functions/getEntity.ts @@ -3,11 +3,10 @@ import { Request, Response } from 'express'; import { OK } from 'http-status-codes'; import FacadeConfig from '../FacadeConfig'; import getJsonQueryParam from '../utils/getJsonQueryParam'; -import handleTransaction from '../utils/handleTransaction'; export default (config: FacadeConfig) => { return async (req: Request, res: Response) => { - await handleTransaction({ config, req, res }, async () => { + await config.handleTransaction({ req, res }, async () => { const { entity } = await config.service.getEntity({ filter: config.constructFilter(getJsonQueryParam(req.query, 'filter')), id: req.params.id, diff --git a/src/functions/patchEntities.ts b/src/functions/patchEntities.ts index 76f077d8..f69a53a2 100644 --- a/src/functions/patchEntities.ts +++ b/src/functions/patchEntities.ts @@ -3,11 +3,10 @@ import { Request, Response } from 'express'; import { OK } from 'http-status-codes'; import FacadeConfig from '../FacadeConfig'; import getJsonQueryParam from '../utils/getJsonQueryParam'; -import handleTransaction from '../utils/handleTransaction'; export default (config: FacadeConfig) => { return async (req: Request, res: Response) => { - await handleTransaction({ config, req, res }, async () => { + await config.handleTransaction({ req, res }, async () => { const { entity } = await config.service.patchEntity({ filter: config.constructFilter(getJsonQueryParam(req.query, 'filter')), id: req.params.id, diff --git a/src/functions/removeEntities.ts b/src/functions/removeEntities.ts index f27b80f8..8847191c 100644 --- a/src/functions/removeEntities.ts +++ b/src/functions/removeEntities.ts @@ -3,11 +3,10 @@ import { Request, Response } from 'express'; import { NO_CONTENT } from 'http-status-codes'; import FacadeConfig from '../FacadeConfig'; import getJsonQueryParam from '../utils/getJsonQueryParam'; -import handleTransaction from '../utils/handleTransaction'; export default (config: FacadeConfig) => { return async (req: Request, res: Response) => { - await handleTransaction({ config, req, res }, async () => { + await config.handleTransaction({ req, res }, async () => { await config.service.removeEntities({ filter: config.constructFilter(getJsonQueryParam(req.query, 'filter')), }); diff --git a/src/functions/removeEntity.ts b/src/functions/removeEntity.ts index 43ef400f..e41343d2 100644 --- a/src/functions/removeEntity.ts +++ b/src/functions/removeEntity.ts @@ -3,11 +3,10 @@ import { Request, Response } from 'express'; import { NO_CONTENT } from 'http-status-codes'; import FacadeConfig from '../FacadeConfig'; import getJsonQueryParam from '../utils/getJsonQueryParam'; -import handleTransaction from '../utils/handleTransaction'; export default (config: FacadeConfig) => { return async (req: Request, res: Response) => { - await handleTransaction({ config, req, res }, async () => { + await config.handleTransaction({ req, res }, async () => { await config.service.removeEntity({ filter: config.constructFilter(getJsonQueryParam(req.query, 'filter')), id: req.params.id, diff --git a/src/functions/replaceEntity.ts b/src/functions/replaceEntity.ts index 95c322ae..1c29ea50 100644 --- a/src/functions/replaceEntity.ts +++ b/src/functions/replaceEntity.ts @@ -3,11 +3,10 @@ import { Request, Response } from 'express'; import { OK } from 'http-status-codes'; import FacadeConfig from '../FacadeConfig'; import getJsonQueryParam from '../utils/getJsonQueryParam'; -import handleTransaction from '../utils/handleTransaction'; export default (config: FacadeConfig) => { return async (req: Request, res: Response) => { - await handleTransaction({ config, req, res }, async () => { + await config.handleTransaction({ req, res }, async () => { const { entity } = await config.service.replaceEntity({ entity: req.body, filter: config.constructFilter(getJsonQueryParam(req.query, 'filter')), diff --git a/src/utils/TransactionHandler.ts b/src/utils/TransactionHandler.ts new file mode 100644 index 00000000..d82800a8 --- /dev/null +++ b/src/utils/TransactionHandler.ts @@ -0,0 +1,17 @@ +import { Response } from 'express'; +import { Request } from 'express-serve-static-core'; + +export interface Opts { + readonly req: Request; + readonly res: Response; +} + +export interface HandlerOpts { + readonly transactionId: string; +} + +export type Handler = (opts: HandlerOpts) => Promise; + +type TransactionHandler = (opts: Opts, handler: Handler) => Promise; + +export default TransactionHandler; diff --git a/src/utils/handleError.ts b/src/utils/handleError.ts index 8526a823..419043e2 100644 --- a/src/utils/handleError.ts +++ b/src/utils/handleError.ts @@ -42,8 +42,10 @@ const handleError: ErrorHandler = ({ res, err, transactionId }) => { return; } /* istanbul ignore next */ - sendErrorResponse(INTERNAL_SERVER_ERROR, {}); - return; + { + sendErrorResponse(INTERNAL_SERVER_ERROR, {}); + return; + } }; export default handleError; diff --git a/src/utils/handleTransaction.ts b/src/utils/handleTransaction.ts index c0a50b66..43137ce5 100644 --- a/src/utils/handleTransaction.ts +++ b/src/utils/handleTransaction.ts @@ -1,26 +1,14 @@ -import Entity from '@js-entity-repos/core/dist/types/Entity'; -import { Request } from 'express'; -import { Response } from 'express-serve-static-core'; import { v4 as uuid } from 'uuid'; -import FacadeConfig from '../FacadeConfig'; +import handleError from './handleError'; +import TransactionHandler from './TransactionHandler'; -export interface Opts { - readonly config: FacadeConfig; - readonly req: Request; - readonly res: Response; -} - -export interface HandlerOpts { - readonly transactionId: string; -} - -export type Handler = (opts: HandlerOpts) => Promise; - -export default async ({ config, req, res }: Opts, handler: Handler) => { +const handleTransaction: TransactionHandler = async ({ req, res }, handler) => { const transactionId = uuid(); try { await handler({ transactionId }); } catch (err) { - config.handleError({ req, res, err, transactionId }); + handleError({ req, res, err, transactionId }); } }; + +export default handleTransaction;