[data-reveal]{opacity:1!important;transform:none!important}
Request bodies and responses
API

Request bodies and responses

Return a plain value for an ordinary response. Use HTTPResult when you need a status code, headers, or a stream, and RequestContext when you need the underlying Node.js request or response.

The HTTPResult class

The HTTPResult class represents an HTTP response. It encapsulates the status code, body, content type, custom headers, and optional streaming.

Basic usage

Route handlers can return plain objects, strings, or HTTPResult instances.

import { Controller, Get, Post, HTTPResult } from "@antelopejs/interface-api";

class ExampleController extends Controller("/examples") {
  @Get()
  getExample() {
    // Returns JSON (content-type: application/json)
    return { status: "success", data: [1, 2, 3] };
  }

  @Get("text")
  getTextExample() {
    // Returns plain text (content-type: text/plain)
    return "This is a text response";
  }

  @Get("custom")
  getCustom() {
    // Returns a fully customized response
    const result = new HTTPResult(200, "<h1>Hello World</h1>", "text/html");
    result.addHeader("X-Custom-Header", "Custom Value");
    return result;
  }
}

Status codes

Set HTTP status codes through the constructor or the setStatus method.

// Through the constructor
const notFound = new HTTPResult(404, "Not Found");

// Through setStatus
const forbidden = new HTTPResult();
forbidden.setStatus(403);

Response body

The body accepts strings, objects, or a custom content type.

// String body (text/plain)
const textResult = new HTTPResult(200, "Hello World");

// Object body (application/json)
const jsonResult = new HTTPResult(200, { message: "Success" });

// Custom content type
const htmlResult = new HTTPResult(200, "<p>HTML content</p>", "text/html");

When the body is an object, HTTPResult automatically serializes it to JSON and sets the content type to application/json.

Custom headers

Add, remove, and retrieve custom response headers.

const result = new HTTPResult(200, "Success");

// Add headers
result.addHeader("X-Rate-Limit", "100");
result.addHeader("X-Rate-Limit-Remaining", "99");

// Remove a header
result.removeHeader("X-Rate-Limit");

// Get all headers
const headers = result.getHeaders();

// Read headers without creating the mutable store
const existingHeaders = result.peekHeaders();

The withHeaders static method

HTTPResult.withHeaders wraps a plain body in a new response. If you pass an existing HTTPResult, it adds headers to that same object and returns it; it does not make a copy. Its optional third argument sets the status only when creating a new response (default 200).

import { HTTPResult } from "@antelopejs/interface-api";

// From a plain body
const result = HTTPResult.withHeaders(
  { message: "Success" },
  { "X-Request-Id": "abc-123" },
);

// From an existing HTTPResult
const original = new HTTPResult(200, { data: "test" });
const withExtra = HTTPResult.withHeaders(original, {
  "Cache-Control": "no-cache",
});
// withExtra === original; original now has the extra header.

Streaming responses

For long-running processes or server-sent events, use the getWriteStream method.

import {
  Controller,
  Get,
  Context,
  WriteStream,
  RequestContext,
} from "@antelopejs/interface-api";
import { PassThrough } from "node:stream";

class StreamController extends Controller("/stream") {
  @Get()
  async streamData(
    @Context() context: RequestContext,
    @WriteStream() stream: PassThrough,
  ) {
    stream.write("Starting stream\n");

    for (let i = 0; i < 10; i++) {
      await new Promise((resolve) => setTimeout(resolve, 1000));
      stream.write(`Data chunk ${i}\n`);
    }

    stream.end("Stream complete\n");
    return context.response;
  }
}

The getWriteStream method accepts an optional content type (defaults to text/plain) and an optional status code (defaults to 200).

The RequestContext interface

The RequestContext interface provides access to all request-related information.

PropertyTypeDescription
rawRequestIncomingMessageThe raw Node.js HTTP request object
rawResponseServerResponseThe raw Node.js HTTP response object
urlURLThe parsed request URL
routeParametersRecord<string, string>Parameters extracted from URL path segments
bodyunknownThe request body data
responseHTTPResultThe response object sent to the client
errorunknownError thrown during processing, if any
connectionunknownWebSocket connection, if applicable

Read request bodies

The ReadBody function reads the raw request body as a Buffer. Buffered request bodies are limited to 1 MiB by default. Requests with a larger Content-Length, or whose received data exceeds the limit, receive HTTP 413 Payload Too Large.

import { Controller, Post, RawBody } from "@antelopejs/interface-api";

class UserController extends Controller("/users") {
  @Post()
  async createUser(@RawBody() body: Buffer) {
    const data = JSON.parse(body.toString());
    return { id: "new-user", ...data };
  }
}

For JSON bodies, use @JSONBody. Parsing checks JSON syntax, not the shape of the resulting value. A TypeScript annotation does not check request data; validate it before accessing fields (for example with API Util). An empty body produces undefined.

import { Controller, Post, JSONBody } from "@antelopejs/interface-api";

class UserController extends Controller("/users") {
  @Post()
  async createUser(@JSONBody() userData: { name: string; email: string }) {
    return { id: "new-user-id", ...userData };
  }
}

Pass a byte limit to @RawBody, @JSONBody, or ReadBody when an endpoint intentionally accepts a larger buffered body:

const TEN_MIBIBYTES = 10 * 1024 * 1024;

class UploadController extends Controller("/uploads") {
  @Post()
  async upload(@RawBody(TEN_MIBIBYTES) body: Buffer) {
    return { bytes: body.length };
  }
}

For bodies that should not be buffered in memory, use @Context() and consume context.rawRequest as a stream instead.

CORS configuration

GetCorsConfig() returns the current CorsConfig. SetCorsConfig(config) replaces it for subsequent requests without restarting the servers. Both functions return promises and require an API implementation.

import { GetCorsConfig, SetCorsConfig } from "@antelopejs/interface-api";

await SetCorsConfig({
  allowedOrigins: [
    "https://app.example.com",
    /^https:\/\/preview-\d+\.example\.com$/,
  ],
  allowedMethods: ["GET", "POST"],
  allowedHeaders: ["Content-Type", "x-antelopejs-auth"],
  credentials: true,
  maxAge: 600,
});

// Preserve other settings when changing one field.
const current = await GetCorsConfig();
await SetCorsConfig({ ...current, maxAge: 300 });
PropertyTypeMeaning
allowedOriginsAllowedOriginA string, a RegExp, or an array of either. Omitting it disables CORS.
allowedMethodsstring[]Allowed cross-origin HTTP methods.
allowedHeadersstring[]Allowed request headers. If omitted, the implementation reflects the client's requested headers.
credentialsbooleanWhether to send Access-Control-Allow-Credentials.
maxAgenumberPreflight cache lifetime in seconds.

All fields are optional. Use explicit trusted origins for credentialed requests. CORS controls browser access to responses; it does not replace authentication or authorization.