diff --git a/app/http/middleware/Test.middleware.ts b/app/http/middleware/Test.middleware.ts index e752c7a..0a5c949 100644 --- a/app/http/middleware/Test.middleware.ts +++ b/app/http/middleware/Test.middleware.ts @@ -1,5 +1,12 @@ import Middleware from '../../../lib/src/http/Middleware.ts' +import {Request} from '../../../lib/src/http/Request.ts' +import {http} from '../../../lib/src/http/response/helpers.ts' +import {HTTPStatus} from '../../../lib/src/const/http.ts' export default class TestMiddleware extends Middleware { - + public async handleRequest(request: Request) { + if ( Math.random() >= 0.5 ) { + return http(HTTPStatus.FORBIDDEN, 'Well, you were unlucky.') + } + } } diff --git a/app/http/routes/home.routes.ts b/app/http/routes/home.routes.ts index c7b0c0d..2aceaea 100644 --- a/app/http/routes/home.routes.ts +++ b/app/http/routes/home.routes.ts @@ -5,5 +5,6 @@ export default { middleware: [], get: { '/': 'controller::Home.get_home', + '/maybe': ['middleware::Test', 'controller::Home.get_home'], }, } as RouterDefinition diff --git a/lib/src/http/Middleware.ts b/lib/src/http/Middleware.ts index 27ced0e..83eca05 100644 --- a/lib/src/http/Middleware.ts +++ b/lib/src/http/Middleware.ts @@ -1,4 +1,6 @@ import AppClass from '../lifecycle/AppClass.ts' +import {Request} from './Request.ts' +import {RouteHandlerReturnValue} from '../unit/Routing.ts' /** * Base class for HTTP middleware. @@ -6,4 +8,13 @@ import AppClass from '../lifecycle/AppClass.ts' */ export default class Middleware extends AppClass { + /** + * Handle the incoming request and apply this middleware. + * @param {Request} request + * @return RouteHandlerReturnValue + */ + public handleRequest(request: Request): RouteHandlerReturnValue { + return + } + } diff --git a/lib/src/http/kernel/module/ApplyRouteHandlers.ts b/lib/src/http/kernel/module/ApplyRouteHandlers.ts index cfef163..3ff79c6 100644 --- a/lib/src/http/kernel/module/ApplyRouteHandlers.ts +++ b/lib/src/http/kernel/module/ApplyRouteHandlers.ts @@ -6,6 +6,7 @@ import {Request} from '../../Request.ts' import ResponseFactory from '../../response/ResponseFactory.ts' import {http, error} from '../../response/helpers.ts' import {HTTPStatus} from '../../../const/http.ts' +import {isRouteHandlerClass} from "../../../unit/Routing.ts"; /** * HTTP kernel module to apply route handlers to the incoming request. @@ -47,7 +48,13 @@ export default class ApplyRouteHandlers extends Module { let current_request: Request = request for ( const handler of request.route.handlers ) { try { - const result = await handler(current_request) + let result + if ( isRouteHandlerClass(handler) ) { + result = await handler.handleRequest(current_request) + } else { + result = await handler(current_request) + } + if ( result instanceof Request ) { // If we got a request instance back, use that for further handlers current_request = result diff --git a/lib/src/unit/Routing.ts b/lib/src/unit/Routing.ts index 7429bb2..ae16ade 100644 --- a/lib/src/unit/Routing.ts +++ b/lib/src/unit/Routing.ts @@ -16,10 +16,22 @@ import {isBindable} from '../lifecycle/AppClass.ts' import {DeepmatchRoute} from "../http/routing/DeepmatchRoute.ts"; import {RegExRoute} from "../http/routing/RegExRoute.ts"; +export type RouteHandlerReturnValue = SyncRouteHandlerReturnValue | AsyncRouteHandlerReturnValue +export type SyncRouteHandlerReturnValue = Request | ResponseFactory | void | undefined +export type AsyncRouteHandlerReturnValue = Promise +export type RouteHandlerFunction = (request: Request) => RouteHandlerReturnValue + +/** + * A class that can handle requests. + */ +export interface RouteHandlerClass { + handleRequest(request: Request): RouteHandlerReturnValue +} + /** * Base type defining a single route handler. */ -export type RouteHandler = (request: Request) => Request | Promise | ResponseFactory | Promise | void | Promise +export type RouteHandler = RouteHandlerFunction | RouteHandlerClass /** * Base type for a collection of route handlers. @@ -49,7 +61,18 @@ export interface RouteDefinition { export function isRouteHandler(what: any): what is RouteHandler { return ( typeof what === 'function' - || typeof what.handleRequest === 'function' + || isRouteHandlerClass(what) + ) +} + +/** + * Returns true if the gievn object is a route handling class. + * @param what + * @return boolean + */ +export function isRouteHandlerClass(what: any): what is RouteHandlerClass { + return ( + what && typeof what.handleRequest === 'function' && what.handleRequest.length === 1 ) }