diff --git a/README.md b/README.md index 397a15e..f916599 100644 --- a/README.md +++ b/README.md @@ -52,13 +52,14 @@ app.get("/", (req) => { schema: { query: [ mustExist("hello"), + (query) => query["hello"] !== "world", ], }, }); ``` -This schema would only allow requests with the `hello` query (for example, -`GET /?hello=yes`). The following helper functions are currently available: +This schema would only allow requests with the `hello` query present and the value not being `"world"` +(for example, `GET /?hello=yes`). The following helper functions are currently available: - `mustExist(key)` - `valueMustBeOfType(key, type)` diff --git a/aqua.ts b/aqua.ts index 290e6c1..2a2ee89 100644 --- a/aqua.ts +++ b/aqua.ts @@ -99,17 +99,10 @@ export interface Options { }; } -export type RoutingSchemaValidationFunction = ( - this: RoutingSchemaValidationContext, - context: RoutingSchemaValidationContext, -) => boolean; - -type BroadestSchemaValidationContextValueTypes = Json; - -type RoutingSchemaValidationContext = Record< - string, - BroadestSchemaValidationContextValueTypes ->; +export type RoutingSchemaValidationFunction = ( + this: Context, + context: Context, +) => boolean | Promise; type RoutingSchemaKeys = | "body" @@ -119,7 +112,9 @@ type RoutingSchemaKeys = | "headers"; type RoutingSchema = { - [requestKey in RoutingSchemaKeys]?: RoutingSchemaValidationFunction[]; + [requestKey in RoutingSchemaKeys]?: RoutingSchemaValidationFunction< + Request[requestKey] + >[]; }; export interface RoutingOptions { @@ -131,7 +126,9 @@ export enum MiddlewareType { Outgoing = "Outgoing", } -export function mustExist(key: string): RoutingSchemaValidationFunction { +export function mustExist( + key: string, +): RoutingSchemaValidationFunction> { return function () { return Object.keys(this).includes(key); }; @@ -140,7 +137,7 @@ export function mustExist(key: string): RoutingSchemaValidationFunction { export function valueMustBeOfType( key: string, type: "string" | "number" | "boolean" | "object" | "undefined", -): RoutingSchemaValidationFunction { +): RoutingSchemaValidationFunction> { return function () { return Object.keys(this).includes(key) && typeof this[key] === type; }; @@ -148,8 +145,8 @@ export function valueMustBeOfType( export function mustContainValue( key: string, - values: BroadestSchemaValidationContextValueTypes[], -): RoutingSchemaValidationFunction { + values: unknown[], +): RoutingSchemaValidationFunction> { return function () { return Object.keys(this).includes(key) && values.includes(this[key]); }; @@ -310,12 +307,12 @@ export default class Aqua { ) as RoutingSchemaKeys[] ) { for ( - const validationFunction of route.options.schema[ + const validationFunction of (route.options.schema[ routingSchemaKey - ] || [] + ] || []) as RoutingSchemaValidationFunction[] ) { const schemaContext = req[routingSchemaKey]; - if (!validationFunction.bind(schemaContext)(schemaContext)) { + if (!(await validationFunction.bind(schemaContext)(schemaContext))) { passedAllValidations = false; break routingSchemaIterator; } diff --git a/tests/uptests.ts b/tests/uptests.ts index 7073b88..7463b22 100644 --- a/tests/uptests.ts +++ b/tests/uptests.ts @@ -102,9 +102,7 @@ registerTest( const content = await requestContent(`/api/v2/hello/world/i`); if (content !== "Not found.") { - throw Error( - "URL parameters don't seem to work", - ); + throw Error("URL parameters don't seem to work"); } }, ); @@ -125,9 +123,7 @@ registerTest( const content = await requestContent(`/api3/hello/test`); if (content === "matched") { - throw Error( - "URL parameters slash positioning caused an error", - ); + throw Error("URL parameters slash positioning caused an error"); } }, ); @@ -272,6 +268,56 @@ registerTest("Parameter schemas working?", async () => { } }); +registerTest("Async schema validation functions passes?", async () => { + app.get( + "/test-parameter-schema-working-async/:hello", + (_req) => "Hello, World!", + { + schema: { + parameters: [ + async (parameters) => { + return await new Promise((r) => r(!!parameters["hello"])); + }, + ], + }, + }, + ); + + const content = await requestContent( + "/test-parameter-schema-working-async/test", + ); + if (content !== "Hello, World!") { + throw Error( + "Async schema validation function didn't pass although it shouldn", + ); + } +}); + +registerTest("Async schema validation functions fails?", async () => { + app.get( + "/test-parameter-schema-working-async-fail/:hello", + (_req) => "Hello, World!", + { + schema: { + parameters: [ + async (parameters) => { + return await new Promise((r) => r(!!parameters["notfound"])); + }, + ], + }, + }, + ); + + const content = await requestContent( + "/test-parameter-schema-working-async-fail/test", + ); + if (content === "Hello, World!") { + throw Error( + "Async schema validation function passed although it shouldn't", + ); + } +}); + registerTest( "Parameter schemas failing if validation functions should return false provided?", async () => {