Request bodies and responses
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.
| Property | Type | Description |
|---|---|---|
rawRequest | IncomingMessage | The raw Node.js HTTP request object |
rawResponse | ServerResponse | The raw Node.js HTTP response object |
url | URL | The parsed request URL |
routeParameters | Record<string, string> | Parameters extracted from URL path segments |
body | unknown | The request body data |
response | HTTPResult | The response object sent to the client |
error | unknown | Error thrown during processing, if any |
connection | unknown | WebSocket 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 });
| Property | Type | Meaning |
|---|---|---|
allowedOrigins | AllowedOrigin | A string, a RegExp, or an array of either. Omitting it disables CORS. |
allowedMethods | string[] | Allowed cross-origin HTTP methods. |
allowedHeaders | string[] | Allowed request headers. If omitted, the implementation reflects the client's requested headers. |
credentials | boolean | Whether to send Access-Control-Allow-Credentials. |
maxAge | number | Preflight 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.
Controllers and routes
Use a controller to group endpoints under one path. Start with a method that returns a value; add hooks only when several routes need the same preparation or response handling.
Read and transform request data
A parameter decorator supplies an argument to your handler from the request. Start with one source per argument, then add a transformation or validation step when the handler needs something other than the raw value.