The Interface API provides a parameter injection system for controller methods. Parameters are automatically extracted from various request sources and processed before being passed to handler methods.
The API extracts parameters from the following sources:
- Route parameters - Segments of the URL path marked with
:paramName - Query parameters - Values from the URL query string
- HTTP headers - Request header values
- Request body - Data submitted in the request body
- Request context - The complete request context object
The @Parameter decorator extracts a single value from route parameters, query strings, or headers.
import { Controller, Get, Parameter } from "@antelopejs/interface-api";
class UsersController extends Controller("/users") {
@Get(":id")
async getUser(@Parameter("id") id: string) {
return { id, name: "Example User" };
}
@Get()
async listUsers(@Parameter("page", "query") page: string) {
// For a request to /users?page=2, page is "2"
return { users: ["user1", "user2"], page };
}
@Get(":userId/posts/:postId")
async getUserPost(
@Parameter("userId") userId: string,
@Parameter("postId") postId: string,
) {
return { userId, postId };
}
}The second argument specifies the source:
| Source | Description | Example |
|---|---|---|
"param" |
Route parameters (default) | /users/:id extracts id |
"query" |
URL query parameters | /users?page=2 extracts page |
"header" |
HTTP request headers | Extracts Authorization header value |
The @MultiParameter decorator extracts multiple values for a parameter as an array. This is useful for query parameters or headers that appear more than once.
import { Controller, Get, MultiParameter } from "@antelopejs/interface-api";
class ProductsController extends Controller("/products") {
@Get("search")
async searchProducts(
@MultiParameter("tag") tags: string[],
) {
// For /products/search?tag=js&tag=api, tags is ["js", "api"]
return { tags, results: ["product1", "product2"] };
}
}The @MultiParameter decorator accepts a source argument of "query" (default) or "header".
The @RawBody decorator provides the raw HTTP request body as a Buffer.
import { Controller, Post, RawBody } from "@antelopejs/interface-api";
class PostsController extends Controller("/posts") {
@Post()
async createPost(@RawBody() postData: Buffer) {
const parsed = JSON.parse(postData.toString());
return { id: "new-post-id", ...parsed };
}
}The @JSONBody decorator parses the HTTP request body as JSON and provides the resulting object.
import { Controller, Post, JSONBody } from "@antelopejs/interface-api";
class UsersController extends Controller("/users") {
@Post()
async createUser(@JSONBody() userData: { name: string; email: string }) {
return { id: "new-user-id", ...userData };
}
}The @Context decorator provides access to the complete RequestContext object.
import { Controller, Get, Context, RequestContext } from "@antelopejs/interface-api";
class InfoController extends Controller("/info") {
@Get()
handleRequest(@Context() ctx: RequestContext) {
const clientIP = ctx.rawRequest.socket.remoteAddress;
const requestUrl = ctx.url.toString();
return { ip: clientIP, url: requestUrl };
}
}The @Result decorator provides access to the HTTPResult response object. This is typically used in postfix handlers to modify the response.
import { Controller, Get, Postfix, Result, HTTPResult } from "@antelopejs/interface-api";
class ResponseController extends Controller("/api") {
@Get("data")
async getData() {
return { data: "example" };
}
@Postfix("get", "data")
async addMetadata(@Result() result: HTTPResult) {
result.addHeader("X-Timestamp", new Date().toISOString());
}
}The @WriteStream decorator provides a writable stream for sending data to the client. This is useful for streaming responses or server-sent events.
import { Controller, Get, WriteStream, Context, RequestContext } from "@antelopejs/interface-api";
import { PassThrough } from "node:stream";
class StreamController extends Controller("/stream") {
@Get()
async streamData(
@Context() context: RequestContext,
@WriteStream("text/event-stream") stream: PassThrough,
) {
stream.write("data: Hello\n\n");
setTimeout(() => {
stream.write("data: World\n\n");
stream.end();
}, 1000);
return context.response;
}
}The @Connection decorator provides access to the WebSocket connection object. It can only be used with @WebsocketHandler.
import { Controller, WebsocketHandler, Connection } from "@antelopejs/interface-api";
class ChatController extends Controller("/chat") {
@WebsocketHandler()
handleChat(@Connection() connection: any) {
connection.on("message", (data: string) => {
connection.send("Received: " + data);
});
}
}Both @Parameter and @MultiParameter (as well as @RawBody, @JSONBody, @Context, and @Connection) can be applied to class properties. The property values are automatically populated from the request for each handler invocation.
import { Controller, Get, Parameter, MultiParameter } from "@antelopejs/interface-api";
class ConfigurableController extends Controller("/config") {
@Parameter("apiKey", "header")
private apiKey!: string;
@MultiParameter("tags", "query")
private tags!: string[];
@Get()
async getConfig() {
return {
authenticated: Boolean(this.apiKey),
appliedTags: this.tags,
};
}
}Handler methods can accept multiple decorated parameters from different sources.
import { Controller, Put, Parameter, JSONBody } from "@antelopejs/interface-api";
class ArticlesController extends Controller("/articles") {
@Put(":id")
async updateArticle(
@Parameter("id") id: string,
@JSONBody() data: { title: string; content: string },
) {
return { id, ...data, updated: true };
}
}Note: Each parameter should have exactly one provider decorator. Do not apply
@Parameterto a parameter that already has@RawBody,@JSONBody, or another provider.
The API uses a system of providers and modifiers to process parameters.
A parameter provider extracts the initial value from the request. The SetParameterProvider function registers a custom provider.
import {
SetParameterProvider,
ReadBody,
RequestContext,
} from "@antelopejs/interface-api";
import { MakeParameterDecorator } from "@antelopejs/interface-core/decorators";
const RawBody = MakeParameterDecorator((target, key, param) =>
SetParameterProvider(target, key, param, (context: RequestContext) => {
return ReadBody(context);
}),
);A parameter modifier transforms the value after the provider runs. Unlike providers, you can chain multiple modifiers on a single parameter. The AddParameterModifier function registers a modifier.
import {
AddParameterModifier,
RequestContext,
} from "@antelopejs/interface-api";
import { MakeParameterDecorator } from "@antelopejs/interface-core/decorators";
const EnsureNumber = MakeParameterDecorator((target, key, param) =>
AddParameterModifier(target, key, param, (context: RequestContext, value: unknown) => {
const num = Number(value);
return isNaN(num) ? 0 : num;
}),
);Use custom modifiers alongside built-in decorators:
import { Controller, Get, Parameter } from "@antelopejs/interface-api";
class ExampleController extends Controller("/example") {
@Get(":id")
async getExample(@Parameter("id") @EnsureNumber() id: number) {
return { id, doubled: id * 2 };
}
}The @Transform decorator applies a transformation function to any parameter value.
import { Controller, Get, Parameter, Transform, RequestContext } from "@antelopejs/interface-api";
function parseId(context: RequestContext, value: unknown): number {
return parseInt(value as string, 10);
}
class ItemController extends Controller("/items") {
@Get(":id")
getItem(@Parameter("id") @Transform(parseId) id: number) {
return { id };
}
}Parameters follow a processing chain from extraction to injection:
Provider => [Modifier 1] => [Modifier 2] => ... => Parameter/Property
The provider runs first to extract the raw value, then each modifier transforms the value in sequence before the final result is passed to the handler.