Skip to Content
Drash v3 is in beta. APIs may change.

Handlers

A chain is a linked list of handlers. Each one does its work, then passes an input object to the next.

import { Handler } from "@drashland/drash/standard/handlers/Handler.js"; class Timer extends Handler { override handle<Output>(input: unknown): Promise<Output> { console.time("request"); return super.sendToNextHandler<Output>(input); } }

Handler

The base class. Implements IHandler.

handle<Output>(input)

public handle<Output>(input: any): Promise<Output>

The entry point. The base implementation forwards straight to the next handler, so a subclass that overrides it is expected to call sendToNextHandler() when it is done.

The input is deliberately untyped. Handlers mutate and enrich it as it travels, so what the last handler sees is not what the first received.

sendToNextHandler<Output>(input)

public sendToNextHandler<Output>(input: any): Promise<Output>

Passes the input along. Throws if there is no next handler:

Handler {name} has no next handler

The last handler in a chain must therefore return a value rather than forward one. In the request chain that is ResourceCaller, which calls your resource and returns what it returned.

setNext(handler)

public setNext(handler: Handler): Handler

Links handler after this one and returns the handler it was given, not this. That return is what lets a whole chain be linked in one pass:

a.setNext(b).setNext(c); // a -> b -> c

The Request Chain’s Handlers

Application.builder() links these five, in this order. The order is fixed and is not the consumer’s to change.

#HandlerWhat it does
1RequestValidatorRejects input with no readable url or method
2ResourcesIndexMatches input.url against every resource’s paths
3ResourceNotFoundHandlerThrows 404 when the index found nothing
4RequestParamsParserAttaches the non-enumerable params object to the request
5ResourceCallerCalls resource[METHOD](request) and returns the result

RequestValidator

Throws HTTPError(Status.UnprocessableEntity) — a 422 — with one of three messages:

MessageCause
Request could not be readInput is falsy, or is not an object
Request HTTP method could not be readNo method property, or it is not a string
Request URL could not be readNo url property, or it is not a string

ResourcesIndex

Builds a URLPattern per resource path and matches the request URL against them. It appends {/}? to each path, which is why a trailing slash matches either way, and it caches results by fully-qualified URL.

Its constructor takes the URLPattern-like class to use — see URLPattern.

ResourceNotFoundHandler

Throws HTTPError(Status.NotFound) when the index produced no result. Throws HTTPError(Status.InternalServerError) with Request could not be read if the input itself is malformed at this stage.

RequestParamsParser

Defines params on the request with Object.defineProperty, non-enumerable, exposing pathParam(name) and queryParam(name). See Handling Requests.

Exports the WithParams type, which the HTTP module re-exports as HTTPRequest.

ResourceCaller

Uppercases input.request.method and calls input.resource[method](input.request). Whatever that returns becomes the resolved value of app.handle().

AbstractChainBuilder

The base for chain builders — it is what wires these handlers together. See AbstractChainBuilder.

AbstractSearchIndex

A base class for defining objects that have a cache and lookup state.

The ResourcesIndex class extends this — caching resource so routing a request to a resource becomes a simple lookup.

Notes

Writing Your Own Handler

Two rules cover it: call sendToNextHandler() unless you are last, and return a promise. handle() is called inside a promise chain, so throwing synchronously and rejecting are equivalent from the caller’s side — both land in app.handle().catch().

A handler that needs to run after the resource cannot be expressed this way, because the chain has no return path. That is what middleware is for — it wraps the resource rather than preceding it.

Last updated on