API Controllers
Create a controller
The Controller function creates a controller class bound to a root location path.
import { Controller } from "@antelopejs/interface-api";
class MyController extends Controller("/api") {
// Route handlers go here
}
Controller hierarchy
Controllers support hierarchical nesting through the extend method. Each sub-controller inherits its parent's path prefix.
import { Controller } from "@antelopejs/interface-api";
// Handles routes at /api
class ApiController extends Controller("/api") {
// API methods
}
// Handles routes at /api/users
class UsersController extends ApiController.extend("users") {
// User-specific methods
}
Partial controllers
The PartialController function creates a controller that shares the same location as an existing controller. This is useful when you want to split routes across multiple files while sharing the same controller context and computed properties.
import { Controller, PartialController, Get } from "@antelopejs/interface-api";
// Original controller
class UsersController extends Controller("/users") {
@Get()
async listUsers() {
return { users: [] };
}
}
// Partial controller at the same /users path
class UsersAdminController extends PartialController(UsersController) {
@Get("admin")
async listAdminUsers() {
return { admins: [] };
}
}
Controller instances
Each HTTP request creates a new controller instance. The GetControllerInstance function retrieves a controller instance for the current request context, which is useful for reusing functionality across controllers.
import {
GetControllerInstance,
Controller,
Get,
RequestContext,
Context,
} from "@antelopejs/interface-api";
class UserController extends Controller("/users") {
async fetchUser(id: string) {
// Shared logic
return { id, name: "Example User" };
}
}
class OrderController extends Controller("/orders") {
@Get(":id")
async getOrder(@Context() context: RequestContext) {
// Reuse UserController logic within the current request
const userCtrl = await GetControllerInstance(UserController, context);
const user = await userCtrl.fetchUser("user-123");
return { order: { id: "order-1", user } };
}
}
The function ensures that computed properties and injected parameters are properly initialized before returning the instance.
Route handlers
Controllers contain methods decorated with HTTP method decorators that define route handlers.
import { Controller, Get, Post, Delete, HTTPResult } from "@antelopejs/interface-api";
class UsersController extends Controller("/users") {
@Get()
async listUsers() {
return { users: ["user1", "user2"] };
}
@Get(":id")
async getUser() {
return { id: "user123", name: "Sample User" };
}
@Post()
async createUser() {
return new HTTPResult(201, { id: "new-user-id", name: "New User" });
}
@Delete(":id")
async deleteUser() {
return new HTTPResult(204);
}
}
Handler modes
The API supports different handler modes that control when and how a method executes.
Prefix handlers
Prefix handlers run before the main handler. They are ideal for authentication, validation, and request preprocessing. If a prefix handler returns a value, that value becomes the response and the main handler is skipped.
import { Controller, Get, Prefix, HTTPResult } from "@antelopejs/interface-api";
class UsersController extends Controller("/users") {
@Prefix("get", ":id")
async validateUserExists() {
const userExists = true; // Check database
if (!userExists) {
return new HTTPResult(404, { error: "User not found" });
}
// Returning nothing allows execution to continue to the main handler
}
@Get(":id")
async getUser() {
return { id: "user123", name: "Sample User" };
}
}
Postfix handlers
Postfix handlers run after the main handler completes. They are useful for response modification, logging, and cleanup.
Warning: If a postfix handler returns a value, all subsequent postfix handlers are skipped.
import { Controller, Get, Postfix, Result, HTTPResult } from "@antelopejs/interface-api";
class UsersController extends Controller("/users") {
@Get(":id")
async getUser() {
return { id: "user123", name: "Sample User" };
}
@Postfix("get", ":id")
async logUserAccess(@Result() result: HTTPResult) {
result.addHeader("X-Accessed-At", new Date().toISOString());
}
}
Monitor handlers
Monitor handlers run after request processing completes, regardless of success or failure. Their return value is ignored. Use them for logging, metrics, or other observation tasks.
import { Controller, Get, Monitor, Context, RequestContext } from "@antelopejs/interface-api";
class UsersController extends Controller("/users") {
@Get(":id")
async getUser() {
return { id: "user123", name: "Sample User" };
}
@Monitor("get", ":id")
async logRequest(@Context() ctx: RequestContext) {
const status = ctx.response.getStatus();
const message = ctx.error ? String(ctx.error) : "ok";
console.log(`GET /users/:id -> ${status} (${message})`);
}
}
WebSocket handlers
WebSocket handlers manage persistent connections using the @WebsocketHandler decorator.
import { Controller, WebsocketHandler, Connection } from "@antelopejs/interface-api";
class ChatController extends Controller("/chat") {
@WebsocketHandler()
async handleChat(@Connection() connection: any) {
connection.on("message", (data: string) => {
connection.send("Echo: " + data);
});
connection.on("close", () => {
console.log("Connection closed");
});
}
}
Handler priority
Handlers can be assigned priorities to control execution order. This is especially useful when multiple prefix or postfix handlers match the same route.
import { Controller, Prefix, HandlerPriority, HTTPResult } from "@antelopejs/interface-api";
class SecuredController extends Controller("/api") {
@Prefix("get", "*", HandlerPriority.HIGHEST)
async checkAuthentication() {
const isAuthenticated = true;
if (!isAuthenticated) {
return new HTTPResult(401, { error: "Unauthorized" });
}
}
@Prefix("get", "*", HandlerPriority.HIGH)
async checkAuthorization() {
const isAuthorized = true;
if (!isAuthorized) {
return new HTTPResult(403, { error: "Forbidden" });
}
}
}
The available priority levels are:
| Priority | Value | Description |
|---|---|---|
HandlerPriority.HIGHEST | 0 | Executes first |
HandlerPriority.HIGH | 1 | High priority |
HandlerPriority.NORMAL | 2 | Default priority |
HandlerPriority.LOW | 3 | Low priority |
HandlerPriority.LOWEST | 4 | Executes last |
The Listen function
The Listen function starts listening on all configured servers.
import { Listen } from "@antelopejs/interface-api";
await Listen();