Skip to content

Middleware

keiro also supports a middleware.ts file which is called before each route, to define a middleware:

src/routes/middleware.ts
import { defineMiddleware } from "keiro";
export default defineMiddleware((event, next) => {
return next(event);
});

API Reference

Middlewares take 2 arguments:

  • RequestEvent: Contains the request, url, params, cookies and request locals.
  • Next: which represent the next handler in the chain.

And must return a Response object.

Middlewares can be defined in any of these ways:

  1. Declaring a function.

    import type { RequestEvent, Next } from "keiro/types";
    export default function middleware(event: RequestEvent, next: Next) {
    return next(event);
    }
  2. Using the defineMiddleware helper.

    import { defineMiddleware } from "keiro";
    export default defineMiddleware((event, next) => {
    return next(event);
    })
  3. Using the Middleware type.

    import type { Middleware } from "keiro/types";
    export default ((event, next) => {
    return next(event);
    }) satisfies Middleware;

Chaining multiple middlewares

You can use multiple middlewares in a row using the sequence helper.

import { sequence } from "keiro";
export default sequence(errorHandler(), logging(), auth())

Examples

Logging middleware

src/lib/middlewares/logging.ts
import { defineMiddleware } from "keiro";
export const logging = defineMiddleware(async (event, next) => {
const request = event.request;
const now = new Date();
// Get the response
const response = await next(event);
const elapsed = Date.now() - now.getTime();
const duration = `${elapsed.toFixed(2)}ms`;
const method = request.method;
const path = event.url.pathname;
const isOk = response.ok ? "" : "";
console.log(`${isOk} [${now.toISOString()}] ${method} ${path} ${duration}`);
})

Error Handler middleware

src/lib/middlewares/error_handler.ts
import { defineMiddleware } from "keiro";
export const errorHandler = defineMiddleware(async (event, next) => {
try {
const response = await next(event);
return response;
}
catch (err) {
console.error(err);
return Response.json(
{ error: "Internal error"},
{ status: 500 }
)
}
})

Timeout middleware

src/lib/middlewares/timeout.ts
import type { Middleware } from "keiro/types";
const delay = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));
class TimeoutError extends Error {}
export const timeout = (ms: number): Middleware => {
return async (event, next) => {
try {
const responsePromise = next(event);
const errorPromise = delay(ms).then(() => Promise.reject(new TimeoutError()));
const response = await Promise.race([responsePromise, errorPromise]);
return response;
} catch (err) {
if (err instanceof TimeoutError) {
return Response.json({ error: "Timeout" }, { status: 408 });
}
throw err;
}
};
};

Auth middleware

src/lib/middlewares/auth.ts
import { defineMiddleware } from "keiro";
import { getSession } from "@/lib/auth";
export const auth = defineMiddleware(async (event, next) => {
const session = await getSession(event.cookies);
if (!session) {
return new Response(null, { status: 401 });
}
return next(event);
})