The handler

The createKaitoHandler function is a very minimal part of Kaito, it simply wraps all your functions together and returns a request -> response function.

import {createKaitoHandler} from '@kaito-http/core';
 
const handler = createKaitoHandler({
	getContext,
	router,
	onError,
});
 
Bun.serve({fetch: handler, port: 3000});

onError

In the example above, you can see I have included a property called onError. This is a function that is called whenever an error is thrown in the request lifecycle. This function should reply with an object that contains a status and message. These will be used to reply to the client.

import {createKaitoHandler} from '@kaito-http/core';
import {ZodError} from 'zod';
 
const handler = createKaitoHandler({
	onError: async ({error, req}) => {
		if (error instanceof ZodError) {
			return {status: 400, message: 'Invalid request'};
		}
 
		return {status: 500, message: 'Internal Server Error'};
	},
	// ...
});

Before/Transform

Kaito has a basic lifecycle for transform/intercepting requests and responses. The most common use case is to add CORS headers.

  • .before() runs before the router is handled. You can return early here to stop the request from being handled by the router.
  • .transform() runs on EVERY response. That includes ones from .before() and ones from the router.
const ALLOWED_ORIGINS = ['http://localhost:3000', 'https://app.example.com'];
 
const server = createKaitoHandler({
	getContext,
	router,
 
	before: async req => {
		if (req.method === 'OPTIONS') {
			return new Response(null, {status: 204}); // Return early to skip the router. This response will be passed to `.transform()`
		}
	},
 
	transform: async (request, response) => {
		const origin = request.headers.get('origin');
 
		// Include CORS headers if the origin is allowed
		if (origin && ALLOWED_ORIGINS.includes(origin)) {
			response.headers.set('Access-Control-Allow-Origin', origin);
			response.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
			response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
			response.headers.set('Access-Control-Max-Age', '86400');
			response.headers.set('Access-Control-Allow-Credentials', 'true');
		}
	},
});

You can also return a response inside of .transform() as well, but we find that there are few use cases for this. Most of the time you’ll only be mutating headers.

This feature was called Before/After in Kaito v2. The functionality has changed a little bit, so migrating to v3 might require some changes.