While most configuration in your Zuplo gateway is set on a per-route or
per-policy basis, there are times when behaviors need to be modified globally.
To plug into the global initialization of your gateway, create a file called
zuplo.runtime.ts in the modules folder with the following code.
Any error thrown in the runtimeInit method will prevent the gateway from
starting and yield a 500 error for all requests. Be sure to add only reliable
code here and use try/catch as appropriate to handle any recoverable
exceptions.
import { RuntimeExtensions } from "@zuplo/runtime";export function runtimeInit(runtime: RuntimeExtensions) { // Extensions go here}
ts
The name of the export must be runtimeInit and must conform to the above
function signature.
Custom Problem (Error) Response Formatter
Zuplo includes built-in error handling that returns errors in the format of the
Problem Details for HTTP APIs proposed standard.
This means that HTTP errors (or other exceptions) will return responses that
look like the following.
If you want to customize this format, you can configure the
problemResponseFormat function and return a Response in the format of your
choice.
import { RuntimeExtensions } from "@zuplo/runtime";export function runtimeInit(runtime: RuntimeExtensions) { runtime.problemResponseFormat = ( { problem, statusText, additionalHeaders }, request, context, ) => { // Build the response body const body = JSON.stringify(problem, null, 2); // Send the response with headers and status return new Response(body, { status: problem.status, statusText, headers: { ...additionalHeaders, "content-type": "application/problem+json", }, }); };}
ts
Hooks
Hooks allow code to be run as part of the request/response pipeline. Hooks can
be created at the API level in zuplo.runtime.ts as shown below or can be added
via a plugin.
All hooks can be either synchronous or asynchronous. To make your hook
asynchronous simply add the async keyword on the function.
The following hooks can be set globally in the zuplo.runtime.ts:
Hook: OnPreRouting
Runs before the request is matched to a route. This is useful if you want to
customize the routing behaviour. Example use cases include:
Routing to a different url based on a header value
import { RuntimeExtensions } from "@zuplo/runtime";export function runtimeInit(runtime: RuntimeExtensions) { runtime.addRequestHook(async (request, context) => { // Add correlation ID const correlationId = crypto.randomUUID(); context.custom.correlationId = correlationId; const headers = new Headers(request.headers); headers.set("X-Correlation-ID", correlationId); // Can return a request or a response. If a response is returned the // pipeline stops and the response is returned. return new ZuploRequest(request, { headers }); }); // Example: Early response for maintenance mode runtime.addRequestHook((request, context) => { if (process.env.MAINTENANCE_MODE === "true") { return new Response("Service temporarily unavailable", { status: 503, headers: { "Retry-After": "3600" }, }); } return request; });}
ts
Hook: OnResponseSending
Runs before a response is sent. Response can be modified. Multiple hooks execute
in the order they were added.
More details.
You can customize how Zuplo handles requests that don't match any route by
setting a custom notFoundHandler:
import { RuntimeExtensions } from "@zuplo/runtime";export function runtimeInit(runtime: RuntimeExtensions) { runtime.notFoundHandler = async (request, context, notFoundOptions) => { // Custom 404 handling const customResponse = { error: "Route not found", message: `The requested path '${new URL(request.url).pathname}' was not found`, timestamp: new Date().toISOString(), requestId: context.requestId, }; return new Response(JSON.stringify(customResponse, null, 2), { status: 404, headers: { "Content-Type": "application/json", "X-Custom-Handler": "true", }, }); };}
ts
Plugin and Handler Extensions
Built-in and custom plugins and handlers can expose their own extensibility. For
example, AWS Lambda handler exposes the ability to
customize the event that's sent when invoking the Lambda function.
The example below shows how to use a route's custom property to set the path on
the outgoing event to a custom value.