feat(http): enhance type safety and extend route context

- Refactor HttpKernel and related interfaces to support generic contexts.
- Add typed query parameters, route params, and state to IContext.
- Introduce HttpMethod type for stricter HTTP method validation.
- Update RouteBuilder and middleware to handle generic contexts.
- Improve test cases to verify compatibility with new types.

Signed-off-by: Max P. <Mail@MPassarello.de>
This commit is contained in:
2025-05-07 12:29:49 +02:00
parent 82a6877485
commit a236fa7c97
22 changed files with 277 additions and 85 deletions

52
src/Types/HttpMethod.ts Normal file
View File

@@ -0,0 +1,52 @@
/**
* A constant list of all supported HTTP methods according to RFC 7231 and RFC 5789.
*
* This array serves both as a runtime value list for validation
* and as the basis for deriving the `HttpMethod` union type.
*
* Note: The list is immutable and should not be modified at runtime.
*/
export const validHttpMethods = [
'GET',
'POST',
'PUT',
'PATCH',
'DELETE',
'HEAD',
'OPTIONS',
] as const;
/**
* A union type representing all valid HTTP methods recognized by this application.
*
* This type is derived directly from the `validHttpMethods` constant,
* ensuring type safety and consistency between type system and runtime checks.
*
* Example:
* ```ts
* const method: HttpMethod = 'POST'; // ✅ valid
* const method: HttpMethod = 'FOO'; // ❌ Type error
* ```
*/
export type HttpMethod = typeof validHttpMethods[number];
/**
* Type guard to verify whether a given value is a valid HTTP method.
*
* This function checks both the type and content of the value
* and is suitable for runtime validation of inputs (e.g., from HTTP requests).
*
* Example:
* ```ts
* if (isHttpMethod(input)) {
* // input is now typed as HttpMethod
* }
* ```
*
* @param value - The value to test (typically a string from a request).
* @returns `true` if the value is a valid `HttpMethod`, otherwise `false`.
*/
export function isHttpMethod(value: unknown): value is HttpMethod {
return typeof value === 'string' &&
validHttpMethods.includes(value as HttpMethod);
}

10
src/Types/Params.ts Normal file
View File

@@ -0,0 +1,10 @@
/**
* Represents route parameters parsed from dynamic segments in the URL path.
*
* This type is typically derived from route definitions with placeholders,
* such as `/users/:id`, which would yield `{ id: "123" }`.
*
* All values are strings and should be considered read-only, as they are
* extracted by the router and should not be modified by application code.
*/
export type Params = Record<string, string>;

12
src/Types/Query.ts Normal file
View File

@@ -0,0 +1,12 @@
/**
* Represents the parsed query parameters from the request URL.
*
* Query parameters originate from the URL search string (e.g. `?filter=active&tags=ts&tags=deno`)
* and may contain single or multiple values per key.
*
* All values are expressed as strings or arrays of strings, depending on how often
* the key occurs. This structure preserves the raw semantics of the query.
*
* For normalized single-value access, prefer custom DTOs or wrapper utilities.
*/
export type Query = Record<string, string | string[]>;

View File

@@ -0,0 +1,25 @@
/**
* A function that modifies or enriches an outgoing HTTP response before it is returned to the client.
*
* This decorator can be used to inject headers (e.g., CORS, security), apply global transformations,
* or wrap responses for logging, analytics, or debugging purposes.
*
* It is called exactly once at the end of the middleware/handler pipeline,
* allowing central response customization without interfering with business logic.
*
* @param res - The original `Response` object produced by the route handler or middleware chain.
* @returns A modified or wrapped `Response` object to be sent back to the client.
*
* @example
* ```ts
* const addCors: ResponseDecorator = (res) => {
* const headers = new Headers(res.headers);
* headers.set("Access-Control-Allow-Origin", "*");
* return new Response(res.body, {
* status: res.status,
* headers,
* });
* };
* ```
*/
export type ResponseDecorator = (res: Response) => Response;

9
src/Types/State.ts Normal file
View File

@@ -0,0 +1,9 @@
/**
* Represents the per-request state object shared across the middleware pipeline.
*
* This type defines the base structure for custom state definitions,
* which can be extended with concrete fields like user data, request metadata, etc.
*
* Custom `TState` types must extend this base to ensure compatibility.
*/
export type State = Record<string, unknown>;

7
src/Types/mod.ts Normal file
View File

@@ -0,0 +1,7 @@
export { isHttpMethod, validHttpMethods } from './HttpMethod.ts';
export type { HttpMethod } from './HttpMethod.ts';
export type { Params } from './Params.ts';
export type { Query } from './Query.ts';
export type { ResponseDecorator } from './ResponseDecorator.ts';
export type { State } from './State.ts';
export type { RegisterRoute } from './registerRoute.ts';

View File

@@ -0,0 +1,16 @@
import { IContext } from '../Interfaces/IContext.ts';
import { IInternalRoute } from '../Interfaces/mod.ts';
/**
* A type alias for the internal route registration function used by the `HttpKernel`.
*
* This function accepts a fully constructed internal route, including method, matcher,
* middleware chain, and final handler, and registers it for dispatching.
*
* Typically passed into `RouteBuilder` instances to enable fluent API chaining.
*
* @template TContext The context type associated with the route being registered.
*/
export type RegisterRoute<TContext extends IContext = IContext> = (
route: IInternalRoute<TContext>,
) => void;