From 8f048ea72750595016eea4e40fd57291001cff95 Mon Sep 17 00:00:00 2001 From: Peter Somogyvari Date: Mon, 9 Oct 2023 10:21:34 -0700 Subject: [PATCH] feat(common): add express http verb method name string literal type 1. Also ships with a user-defined typescript type-guard so that we can ensure at runtime that the string literal value is indeed one of the valid ExpressJS HTTP verb method names. 2. The primary use-case for this is checking at runtime the HTTP verb name of OpenAPI specifications that are being loaded into the API. [skip ci] Signed-off-by: Peter Somogyvari --- .../http/express-http-verb-method-name.ts | 51 +++++++++++++++++++ .../src/main/typescript/public-api.ts | 16 +++++- .../express-http-verb-method-name.test.ts | 31 +++++++++++ 3 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 packages/cactus-common/src/main/typescript/http/express-http-verb-method-name.ts create mode 100644 packages/cactus-common/src/test/typescript/unit/http/express-http-verb-method-name.test.ts diff --git a/packages/cactus-common/src/main/typescript/http/express-http-verb-method-name.ts b/packages/cactus-common/src/main/typescript/http/express-http-verb-method-name.ts new file mode 100644 index 0000000000..f96cd1593a --- /dev/null +++ b/packages/cactus-common/src/main/typescript/http/express-http-verb-method-name.ts @@ -0,0 +1,51 @@ +/** + * A collection of all the HTTP verb method names that Express.js supports. + * Directly taken from the Express.js type definitions file of the @types/express + * package. + */ +export const ALL_EXPRESS_HTTP_VERB_METHOD_NAMES = [ + "all", + "get", + "post", + "put", + "delete", + "patch", + "options", + "head", +] as const; + +/** + * A type that represents all the HTTP verb method names that Express.js supports. + */ +export type ExpressHttpVerbMethodName = + typeof ALL_EXPRESS_HTTP_VERB_METHOD_NAMES[number]; + +/** + * Custom (user-defined) typescript type-guard that checks whether the given + * value is an Express.js HTTP verb method name or not. + * Useful for verifying at runtime if we can safely call a method on the Express.js + * application object where the method's name is the value of the given variable. + * + * Example: + * + * ```typescript + * import express from "express"; + * import { isExpressHttpVerbMethodName } from "@hyperledger/cactus-core-api-server"; + * const app = express(); + * const methodName = "get"; + * if (isExpressHttpVerbMethodName(methodName)) { + * app[methodName]("/foo", (req, res) => { + * res.send("Hello World!"); + * }); + * ``` + * + * @param x Any value that may or may not be an Express.js HTTP verb method name. + * @returns Whether the given value is an Express.js HTTP verb method name. + */ +export function isExpressHttpVerbMethodName( + x: unknown, +): x is ExpressHttpVerbMethodName { + return ( + typeof x === "string" && ALL_EXPRESS_HTTP_VERB_METHOD_NAMES.includes(x as never) + ); +} diff --git a/packages/cactus-common/src/main/typescript/public-api.ts b/packages/cactus-common/src/main/typescript/public-api.ts index 893eb5f473..23ab9a9219 100755 --- a/packages/cactus-common/src/main/typescript/public-api.ts +++ b/packages/cactus-common/src/main/typescript/public-api.ts @@ -29,7 +29,19 @@ export { export { isRecord } from "./types/is-record"; export { hasKey } from "./types/has-key"; -export { asError, coerceUnknownToError } from "./exception/coerce-unknown-to-error"; -export { createRuntimeErrorWithCause, newRex } from "./exception/create-runtime-error-with-cause"; +export { + asError, + coerceUnknownToError, +} from "./exception/coerce-unknown-to-error"; +export { + createRuntimeErrorWithCause, + newRex, +} from "./exception/create-runtime-error-with-cause"; export { ErrorFromUnknownThrowable } from "./exception/error-from-unknown-throwable"; export { ErrorFromSymbol } from "./exception/error-from-symbol"; + +export { + ALL_EXPRESS_HTTP_VERB_METHOD_NAMES, + ExpressHttpVerbMethodName, + isExpressHttpVerbMethodName, +} from "./http/express-http-verb-method-name"; diff --git a/packages/cactus-common/src/test/typescript/unit/http/express-http-verb-method-name.test.ts b/packages/cactus-common/src/test/typescript/unit/http/express-http-verb-method-name.test.ts new file mode 100644 index 0000000000..abcfdb1104 --- /dev/null +++ b/packages/cactus-common/src/test/typescript/unit/http/express-http-verb-method-name.test.ts @@ -0,0 +1,31 @@ +import { + ALL_EXPRESS_HTTP_VERB_METHOD_NAMES, + ExpressHttpVerbMethodName, + isExpressHttpVerbMethodName, +} from "../../../../main/typescript/public-api"; + +describe("isExpressHttpVerbMethodName", () => { + it("should return true for valid HTTP verb method names", () => { + ALL_EXPRESS_HTTP_VERB_METHOD_NAMES.forEach((methodName) => { + expect(isExpressHttpVerbMethodName(methodName)).toBe(true); + }); + }); + + it("should return false for invalid values", () => { + const invalidValues = [ + 123, // Not a string + 0, // Falsy Number + "invalid", // Not a valid HTTP verb method name + "gEt", // Case-sensitive + "", // Empty string + null, // Null value + undefined, // Undefined value + {}, // Object + [], // Array + ]; + + invalidValues.forEach((value) => { + expect(isExpressHttpVerbMethodName(value)).toBe(false); + }); + }); +});