Core Concepts

Context

A guide to middleware context in Raptor

Introduction

The context object is passed as the first parameter to a middleware function. It includes the HTTP request, the HTTP response, and any additional properties added by previous middleware calls.

Usage

import { type Context, Kernel } from "@raptor/kernel";
 
const app = new Kernel();
 
app.use((context: Context) => {
  const { request, response } = context;
 
  console.log(request, response);
 
  return "Dinosaurs eat man. Woman inherits the earth";
});
 
app.serve();

Request

Raptor uses the standard Web API Request object, giving you access to all its built-in properties and methods without any framework-specific wrappers.

app.use((context: Context) => {
  const { request } = context;
  
  console.log(request.method);
  console.log(request.url);
  console.log(request.headers);
  
  return "Life, uh, finds a way";
});

Common Request Operations

Reading Headers

app.use((context: Context) => {
  const authToken = context.request.headers.get("Authorization");
  const contentType = context.request.headers.get("Content-Type");
  
  return { authToken, contentType };
});

Parsing Request Body

app.use(async (context: Context) => {
  // JSON body
  const data = await context.request.json();
  
  // Form data
  const formData = await context.request.formData();
  
  // Plain text
  const text = await context.request.text();
  
  return { received: data };
});

Reading Query Parameters

app.use((context: Context) => {
  const url = new URL(context.request.url);
 
  const name = url.searchParams.get("name");
  const page = url.searchParams.get("page") || "1";
  
  return { name, page };
});

Checking Request Method

import { MethodNotAllowed } from "@raptor/kernel";
 
app.use((context: Context) => {
  if (context.request.method === "POST") {
    // Handle POST request
  }
  
  if (context.request.method !== "GET") {
    throw new MethodNotAllowed();
  }
  
  return "Clever Girl";
});

Since Raptor doesn't wrap or modify the Request object, you can use any Web API features directly - no need to learn framework-specific methods.

Response

In Raptor, at least one middleware function is required to return a body response to ensure that the request cycle completes successfully. Raptor automatically handles response types through its response processor system. By default, it can process JSON objects, HTML strings, plain text, and raw Response objects. However, you can extend this system with your own custom processors.

Returning JSON

If the middleware response body is an object, it will be automatically recognized as application/json. Consequently, both the Content-Type header and the response body will be appropriately set to reflect this format.

app.use(() => ({
  name: 'Dr Ian Malcolm',
}));

Returning HTML

When a string is returned, the Content-Type header is automatically set to text/plain. However, if the string is detected to contain HTML, the Content-Type header will be automatically adjusted to text/html.

app.use(() => '<h1>Hello, Dr Malcolm!</h1>');

Returning Response Directly

Raptor makes it easy to return simple scalar values as responses, but when you need full control over the output, you can also return a custom Response object directly.

app.use(() => new Response("We spared no expense", { status: 200 }));

Overriding headers

Although it's convenient to return data without configuring a Content-Type, there may be instances where you need to specify a particular header. In such cases, you can proceed as follows:

app.use((context: Context) => {
  context.response.headers.set("Content-Type", "application/hal+json");
 
  return {
    name: "That doesn't look very scary. More like a six-foot turkey."
  }
});

Extending

Response Processors

What are Response Processors?

The Response Manager handles converting your middleware return values into HTTP responses. There are four built-in processors out of the box, but you can add custom ones or override the defaults.

Built-in Processors
TypeHandlesContent-Type
responseResponse objects(preserved from original)
errorError instancesBased on request Accept header
stringString valuestext/plain or text/html
objectObjects/Arraysapplication/json
Creating a custom processor

To create a custom processor, implement the Processor interface:

import type { Context, Processor, ResponseBodyType } from "@raptor/kernel";
 
export default class CustomStringProcessor implements Processor {
  process(body: any, context: Context): Response {
    return new Response("custom string processor: " + body, {
      status: context.response.status,
      headers: context.response.headers,
    });
  }
}
Overriding an existing processor

To override an existing processor with your own, you can do the following:

import { type Context, Kernel, ResponseManager } from "@raptor/kernel";
 
import CustomStringProcessor from "./custom-string-processor.ts";
 
const app = new Kernel();
 
const manager = new ResponseManager();
 
manager.register("string", new CustomStringProcessor());
 
app.setResponseManager(manager);
 
app.use(() => "Hello, Dr Malcom!");
 
app.serve();
 
// custom string processor: Hello, Dr Malcolm!

All strings which are returned from middleware will now use your custom processor.

© 2026 Raptor