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:
@@ -1,11 +1,22 @@
|
||||
import { Params, Query, State } from '../Types/mod.ts';
|
||||
|
||||
/**
|
||||
* Represents the per-request context passed through the middleware pipeline and to the final handler.
|
||||
* Represents the complete context for a single HTTP request,
|
||||
* passed through the middleware pipeline and to the final route handler.
|
||||
*
|
||||
* This context object encapsulates the original HTTP request,
|
||||
* the path parameters extracted from the matched route,
|
||||
* and a mutable state object for sharing information across middlewares and handlers.
|
||||
* This context object encapsulates all relevant runtime data for a request,
|
||||
* including the original request, path parameters, query parameters,
|
||||
* and a shared, mutable application state.
|
||||
*
|
||||
* @template TState Structured per-request state shared across middlewares and handlers.
|
||||
* @template TParams Parsed URL path parameters, typically derived from route templates.
|
||||
* @template TQuery Parsed query string parameters, preserving multi-value semantics.
|
||||
*/
|
||||
export interface IContext {
|
||||
export interface IContext<
|
||||
TState extends State = State,
|
||||
TParams extends Params = Params,
|
||||
TQuery extends Query = Query,
|
||||
> {
|
||||
/**
|
||||
* The original HTTP request object as received by Deno.
|
||||
* Contains all standard fields like headers, method, body, etc.
|
||||
@@ -18,14 +29,25 @@ export interface IContext {
|
||||
*
|
||||
* These parameters are considered read-only and are set by the router.
|
||||
*/
|
||||
params: Record<string, string>;
|
||||
params: TParams;
|
||||
|
||||
/**
|
||||
* A shared, mutable object used to pass arbitrary data between middlewares and handlers.
|
||||
* Query parameters extracted from the request URL's search string.
|
||||
*
|
||||
* Use this field to attach validated user info, auth state, logging context, etc.
|
||||
* Values may occur multiple times (e.g., `?tag=ts&tag=deno`), and are therefore
|
||||
* represented as either a string or an array of strings, depending on occurrence.
|
||||
*
|
||||
* Each key should be well-named to avoid collisions across layers.
|
||||
* Use this field to access filters, flags, pagination info, or similar modifiers.
|
||||
*/
|
||||
state: Record<string, unknown>;
|
||||
query: TQuery;
|
||||
|
||||
/**
|
||||
* A typed, mutable object used to pass structured data between middlewares and handlers.
|
||||
*
|
||||
* This object is ideal for sharing validated input, user identity, trace information,
|
||||
* or other contextual state throughout the request lifecycle.
|
||||
*
|
||||
* Type-safe access to fields is ensured by the generic `TState` type.
|
||||
*/
|
||||
state: TState;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
import { IContext } from './IContext.ts';
|
||||
|
||||
/**
|
||||
* Represents a final request handler responsible for generating a response.
|
||||
* Represents a final request handler responsible for producing an HTTP response.
|
||||
*
|
||||
* The handler is the last step in the middleware pipeline and must return
|
||||
* a valid HTTP `Response`. It has access to all data injected into the
|
||||
* request context, including path parameters and any state added by middleware.
|
||||
* The handler is the terminal stage of the middleware pipeline and is responsible
|
||||
* for processing the incoming request and generating the final `Response`.
|
||||
*
|
||||
* It receives the fully-typed request context, which includes the original request,
|
||||
* parsed route parameters, query parameters, and any shared state populated by prior middleware.
|
||||
*
|
||||
* @template TContext The specific context type for this handler, including typed `state`, `params`, and `query`.
|
||||
*/
|
||||
export interface IHandler {
|
||||
export interface IHandler<TContext extends IContext = IContext> {
|
||||
/**
|
||||
* @param ctx - The complete request context, including parameters and middleware state.
|
||||
* @returns A promise resolving to an HTTP `Response`.
|
||||
* Handles the request and generates a response.
|
||||
*
|
||||
* @param ctx - The complete request context, including request metadata, route and query parameters,
|
||||
* and mutable state populated during the middleware phase.
|
||||
* @returns A `Promise` resolving to an HTTP `Response` to be sent to the client.
|
||||
*/
|
||||
(ctx: IContext): Promise<Response>;
|
||||
(ctx: TContext): Promise<Response>;
|
||||
}
|
||||
|
||||
@@ -1,33 +1,50 @@
|
||||
import { IContext } from './IContext.ts';
|
||||
import { IRouteBuilder } from './IRouteBuilder.ts';
|
||||
import { IRouteDefinition } from './IRouteDefinition.ts';
|
||||
|
||||
/**
|
||||
* Defines the core interface for the HTTP kernel, responsible for route registration,
|
||||
* middleware orchestration, and request dispatching.
|
||||
* Defines the core interface for an HTTP kernel instance, responsible for
|
||||
* registering routes, orchestrating middleware pipelines, and dispatching
|
||||
* incoming HTTP requests to the appropriate handler.
|
||||
*
|
||||
* The kernel operates on a generic `IContext` type, which encapsulates the
|
||||
* request, typed state, route parameters, and query parameters for each request.
|
||||
*
|
||||
* @template TContext The default context type for all registered routes and handlers.
|
||||
*/
|
||||
export interface IHttpKernel {
|
||||
export interface IHttpKernel<TContext extends IContext = IContext> {
|
||||
/**
|
||||
* Registers a new route with a static path pattern or a dynamic matcher.
|
||||
* Registers a new route using a static path or custom matcher.
|
||||
*
|
||||
* This method accepts both conventional route definitions (with path templates)
|
||||
* and advanced matcher-based routes for flexible URL structures.
|
||||
* Returns a route builder that allows chaining middleware and assigning a final handler.
|
||||
* This method is context-generic, allowing temporary overrides for specific routes
|
||||
* if their context differs from the kernel-wide default.
|
||||
*
|
||||
* Returns a route builder that allows chaining middleware and assigning a handler.
|
||||
* @template _TContext Optional context override for the specific route being registered.
|
||||
* Defaults to the kernel's generic `TContext`.
|
||||
*
|
||||
* @param definition - A static or dynamic route definition, including the HTTP method
|
||||
* and either a path pattern or custom matcher function.
|
||||
* @returns A builder interface to attach middleware and define the handler.
|
||||
* @param definition - A route definition containing the HTTP method and either a path
|
||||
* pattern (e.g., `/users/:id`) or a custom matcher function.
|
||||
* @returns A fluent builder interface for attaching middleware and setting the handler.
|
||||
*/
|
||||
route(definition: IRouteDefinition): IRouteBuilder;
|
||||
route<_TContext extends IContext = TContext>(
|
||||
definition: IRouteDefinition,
|
||||
): IRouteBuilder; // IRouteBuilder<_TContext>
|
||||
|
||||
/**
|
||||
* Handles an incoming HTTP request by matching it against registered routes,
|
||||
* executing any associated middleware in order, and invoking the final route handler.
|
||||
* Handles an incoming HTTP request by matching it to a route, executing its middleware,
|
||||
* and invoking the final handler. Automatically populates route parameters (`ctx.params`),
|
||||
* query parameters (`ctx.query`), and initializes an empty mutable state (`ctx.state`).
|
||||
*
|
||||
* This method serves as the main entry point to integrate with `Deno.serve`.
|
||||
* This method is typically passed directly to `Deno.serve()` as the request handler.
|
||||
*
|
||||
* @param request - The incoming HTTP request object.
|
||||
* @template _TContext Optional override for the context type of the current request.
|
||||
* Useful for testing or simulated requests. Defaults to the kernel’s `TContext`.
|
||||
*
|
||||
* @param request - The incoming HTTP request to dispatch.
|
||||
* @returns A promise resolving to the final HTTP response.
|
||||
*/
|
||||
handle(request: Request): Promise<Response>;
|
||||
handle<_TContext extends IContext = TContext>(
|
||||
request: Request,
|
||||
): Promise<Response>;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { HttpMethod } from '../Types/mod.ts';
|
||||
import { IHandler } from './IHandler.ts';
|
||||
import { IMiddleware } from './IMiddleware.ts';
|
||||
import { IContext } from './mod.ts';
|
||||
|
||||
/**
|
||||
* Represents an internally registered route within the HttpKernel.
|
||||
@@ -7,12 +9,12 @@ import { IMiddleware } from './IMiddleware.ts';
|
||||
* Contains all data required to match an incoming request and dispatch it
|
||||
* through the associated middleware chain and final handler.
|
||||
*/
|
||||
export interface IInternalRoute {
|
||||
export interface IInternalRoute<TContext extends IContext = IContext> {
|
||||
/**
|
||||
* The HTTP method (e.g. 'GET', 'POST') that this route responds to.
|
||||
* The method should always be in uppercase.
|
||||
*/
|
||||
method: string;
|
||||
method: HttpMethod;
|
||||
|
||||
/**
|
||||
* A matcher function used to determine whether this route matches a given request.
|
||||
@@ -33,10 +35,10 @@ export interface IInternalRoute {
|
||||
/**
|
||||
* An ordered list of middleware functions to be executed before the handler.
|
||||
*/
|
||||
middlewares: IMiddleware[];
|
||||
middlewares: IMiddleware<TContext>[];
|
||||
|
||||
/**
|
||||
* The final handler that generates the HTTP response after all middleware has run.
|
||||
*/
|
||||
handler: IHandler;
|
||||
handler: IHandler<TContext>;
|
||||
}
|
||||
|
||||
@@ -3,18 +3,23 @@ import { IContext } from './IContext.ts';
|
||||
/**
|
||||
* Represents a middleware function in the HTTP request pipeline.
|
||||
*
|
||||
* Middleware can perform tasks such as logging, authentication, validation,
|
||||
* or response transformation. It receives the current request context and
|
||||
* a `next()` function to delegate control to the next middleware or final handler.
|
||||
* Middleware is a core mechanism to intercept, observe, or modify the request lifecycle.
|
||||
* It can be used for tasks such as logging, authentication, input validation,
|
||||
* metrics collection, or response transformation.
|
||||
*
|
||||
* To stop the request pipeline, a middleware can return a `Response` directly
|
||||
* without calling `next()`.
|
||||
* Each middleware receives a fully-typed request context and a `next()` function
|
||||
* to invoke the next stage of the pipeline. Middleware may choose to short-circuit
|
||||
* the pipeline by returning a `Response` early.
|
||||
*
|
||||
* @template TContext The specific context type for this middleware, including state, params, and query information.
|
||||
*/
|
||||
export interface IMiddleware {
|
||||
export interface IMiddleware<TContext extends IContext = IContext> {
|
||||
/**
|
||||
* @param ctx - The request context, containing the request, path parameters, and shared state.
|
||||
* @param next - A function that continues the middleware pipeline. Returns the final `Response`.
|
||||
* @returns A promise resolving to an HTTP `Response`.
|
||||
* Handles the request processing at this middleware stage.
|
||||
*
|
||||
* @param ctx - The full request context, containing request, params, query, and typed state.
|
||||
* @param next - A continuation function that executes the next middleware or handler in the pipeline.
|
||||
* @returns A `Promise` resolving to an HTTP `Response`, either from this middleware or downstream.
|
||||
*/
|
||||
(ctx: IContext, next: () => Promise<Response>): Promise<Response>;
|
||||
(ctx: TContext, next: () => Promise<Response>): Promise<Response>;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { IHandler } from './IHandler.ts';
|
||||
import { IInternalRoute } from './IInternalRoute.ts';
|
||||
import { IMiddleware } from './IMiddleware.ts';
|
||||
import { IRouteDefinition } from './IRouteDefinition.ts';
|
||||
import { IContext } from './mod.ts';
|
||||
|
||||
export interface IRouteBuilderFactory {
|
||||
new (
|
||||
@@ -15,7 +16,7 @@ export interface IRouteBuilderFactory {
|
||||
* Provides a fluent API to build a single route configuration by chaining
|
||||
* middleware and setting the final request handler.
|
||||
*/
|
||||
export interface IRouteBuilder {
|
||||
export interface IRouteBuilder<TContext extends IContext = IContext> {
|
||||
/**
|
||||
* Adds a middleware to the current route.
|
||||
* Middleware will be executed in the order of registration.
|
||||
@@ -23,7 +24,9 @@ export interface IRouteBuilder {
|
||||
* @param mw - A middleware function.
|
||||
* @returns The route builder for further chaining.
|
||||
*/
|
||||
middleware(mw: IMiddleware): IRouteBuilder;
|
||||
middleware<_TContext extends IContext = TContext>(
|
||||
mw: IMiddleware<_TContext>,
|
||||
): IRouteBuilder<_TContext>;
|
||||
|
||||
/**
|
||||
* Sets the final request handler for the route.
|
||||
@@ -31,5 +34,7 @@ export interface IRouteBuilder {
|
||||
*
|
||||
* @param handler - The function to execute when this route is matched.
|
||||
*/
|
||||
handle(handler: IHandler): void;
|
||||
handle<_TContext extends IContext = TContext>(
|
||||
handler: IHandler<_TContext>,
|
||||
): void;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { HttpMethod } from '../Types/mod.ts';
|
||||
import { IRouteMatcher } from './IRouteMatcher.ts';
|
||||
|
||||
/**
|
||||
@@ -10,7 +11,7 @@ export interface IStaticRouteDefinition {
|
||||
/**
|
||||
* The HTTP method this route should match (e.g. "GET", "POST").
|
||||
*/
|
||||
method: string;
|
||||
method: HttpMethod;
|
||||
|
||||
/**
|
||||
* A static path pattern for the route, which may include named parameters
|
||||
@@ -29,7 +30,7 @@ export interface IDynamicRouteDefinition {
|
||||
/**
|
||||
* The HTTP method this route should match (e.g. "GET", "POST").
|
||||
*/
|
||||
method: string;
|
||||
method: HttpMethod;
|
||||
|
||||
/**
|
||||
* A custom matcher function that receives the parsed URL and raw request.
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
@@ -1,13 +1,12 @@
|
||||
export type { IContext } from './IContext.ts';
|
||||
export type { IMiddleware } from './IMiddleware.ts';
|
||||
export type { IHandler } from './IHandler.ts';
|
||||
export type { IHttpKernel } from './IHttpKernel.ts';
|
||||
export type { IInternalRoute } from './IInternalRoute.ts';
|
||||
export type { IMiddleware } from './IMiddleware.ts';
|
||||
export type { IRouteBuilder, IRouteBuilderFactory } from './IRouteBuilder.ts';
|
||||
export type {
|
||||
IDynamicRouteDefinition,
|
||||
IRouteDefinition,
|
||||
IStaticRouteDefinition,
|
||||
} from './IRouteDefinition.ts';
|
||||
export type { IInternalRoute } from './IInternalRoute.ts';
|
||||
export type { IRouteMatcher } from './IRouteMatcher.ts';
|
||||
export type { ResponseDecorator } from './ResponseDecorator.ts';
|
||||
export type { IRouteMatcher, IRouteMatcherFactory } from './IRouteMatcher.ts';
|
||||
|
||||
Reference in New Issue
Block a user