diff --git a/package-lock.json b/package-lock.json index 228fa9abbc..81330e44cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -960,6 +960,11 @@ } } }, + "express-async-handler": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/express-async-handler/-/express-async-handler-1.1.4.tgz", + "integrity": "sha512-HdmbVF4V4w1q/iz++RV7bUxIeepTukWewiJGkoCKQMtvPF11MLTa7It9PRc/reysXXZSEyD4Pthchju+IUbMiQ==" + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -1193,6 +1198,11 @@ "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", "dev": true }, + "get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==" + }, "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", diff --git a/package.json b/package.json index 29552f053f..136ee062a8 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,8 @@ }, "dependencies": { "express": "^4.17.1", + "express-async-handler": "^1.1.4", + "get-port": "^5.1.1", "mssql": "^6.2.0", "mysql": "^2.18.1", "oracledb": "^4.2.0", diff --git a/src/app.ts b/src/app.ts index ea4b3e7745..59eed4adcd 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,5 +1,14 @@ -import express from "express"; +import express from 'express'; +import asyncHandler from 'express-async-handler'; +import APIError, { errorHandler, ErrorCode } from './error'; -const app = express(); +const app = express() + .get( + '/', + asyncHandler(async (req, res, next) => { + throw new APIError(ErrorCode.NOT_FOUND, 'Route `/` not found'); + }) + ) + .use(errorHandler); export default app; diff --git a/src/error.ts b/src/error.ts new file mode 100644 index 0000000000..67196d55c8 --- /dev/null +++ b/src/error.ts @@ -0,0 +1,39 @@ +import { ErrorRequestHandler } from 'express'; + +export enum ErrorCode { + NOT_FOUND = 'NOT_FOUND', +} + +enum HTTPStatus { + NOT_FOUND = 404, +} + +export const errorHandler: ErrorRequestHandler = (error: APIError, req, res, next) => { + res.status(error.status); + + const response: any = { + error: { + code: error.code, + message: error.message, + }, + }; + + if ((process.env.NODE_ENV = 'development')) { + response.error.stack = error.stack; + } + + res.json(response); +}; + +export default class APIError extends Error { + status: HTTPStatus; + code: ErrorCode; + + constructor(code: ErrorCode, message: string) { + super(message); + this.status = HTTPStatus[code] || 500; + this.code = code; + + Error.captureStackTrace(this, this.constructor); + } +} diff --git a/src/server.ts b/src/server.ts index a2b7447d19..a80f8b142f 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,8 +1,11 @@ -import app from "./app"; -import logger from "./logger"; +import app from './app'; +import logger from './logger'; +import getPort from 'get-port'; -const port = process.env.PORT || 3000; +(async () => { + const port = process.env.PORT || (await getPort({ port: 3000 })); -app.listen(port, () => { - logger.info(`Server started at port ${port}`); -}); + app.listen(port, () => { + logger.info(`Server started at port ${port}`); + }); +})(); diff --git a/tsconfig.json b/tsconfig.json index c294e94f5c..771dcbe038 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,4 +10,4 @@ "lib": [ "es2015" ] -} \ No newline at end of file +}