Make Custom HTTP APIs for your Golem App
Golem’s Gateway service not only exposes the low-level REST API for invocations but also provides a way to expose agent methods as HTTP APIs.
In Golem 1.5, HTTP endpoints are defined directly in agent code using language-native decorators and macros — no YAML route definitions or scripting languages needed.
Mount Points
Every agent that wants to expose HTTP endpoints must first define a mount point — the base URL prefix under which all its endpoints are available. The mount path can contain placeholders like {name} that map to the agent’s constructor parameters.
TypeScript
@agent({
mount: '/task-agents/{name}',
})
export class Tasks extends BaseAgent {
constructor(readonly name: string) { super(); }
// ...
}If there are multiple agent constructor parameters, they all have to be mapped in the mount path.
Endpoints
Once the mount is defined, individual agent methods can be exposed as HTTP endpoints. Each endpoint specifies an HTTP method and a path suffix relative to the mount point. Path placeholders are mapped to method parameters. Parameters not mapped through the path or headers are taken from the request body.
TypeScript
@endpoint({ post: "/tasks" })
async createTask(request: CreateTaskRequest): Promise<Task> {
// ...
}
@endpoint({ get: "/tasks" })
async getTasks(): Promise<Task[]> {
// ...
}
@endpoint({ post: "/tasks/{id}/complete" })
async completeTask(id: number): Promise<Task | null> {
// ...
}Supported HTTP methods: get, post, put, delete, patch, head, options, connect, trace, and custom (for arbitrary method strings, TypeScript only).
Query Parameters
Query parameters can be bound to method parameters using standard HTTP query syntax in the endpoint path:
TypeScript
@endpoint({ get: "/search?q={query}&limit={limit}" })
async search(query: string, limit: number): Promise<SearchResult[]> {
// ...
}Header Mapping
Custom HTTP headers can be mapped to function parameters:
TypeScript
@endpoint({
get: '/example',
headers: { 'X-Foo': 'location', 'X-Bar': 'name' },
})
async example(location: string, name: string): Promise<string> {
// ...
}Catch-all Path Segments
The {*variable} syntax captures all remaining path segments. It must be the last segment in the path:
TypeScript
@endpoint({ get: "/files/{*rest}" })
async serveFile(rest: string): Promise<FileData> {
// ...
}Response Conventions
Return types control the HTTP response:
| Return type | HTTP response |
|---|---|
A value (e.g. Task) | 200 OK with JSON body |
Option<T> / T | null | Some/non-null → 200; None/null → 404 Not Found |
Result<T, E> | Ok → 200; Err → 400 Bad Request with JSON error |
void / () | 204 No Content |
Binary Request Bodies
Use the UnstructuredBinary type to receive raw binary data in the request body:
TypeScript
@endpoint({ post: "/upload" })
async upload(file: UnstructuredBinary): Promise<number> {
// ...
}CORS
CORS can be configured at the mount level (applies to all endpoints) and optionally overridden per endpoint:
TypeScript
@agent({
mount: '/api/{name}',
cors: ['https://app.example.com'],
})
export class MyAgent extends BaseAgent {
// All endpoints inherit the mount-level CORS setting
@endpoint({ get: "/public", cors: ["*"] })
async getPublic(): Promise<Data> {
// This endpoint adds additional allowed origins
}
}Per-endpoint CORS settings are unioned with the mount-level settings.
Authentication
Golem API gateway has built-in authentication support. Authentication can be enabled at the mount level or per endpoint using auth = true. See the API authentication page for setup details.
TypeScript
@agent({
mount: '/secure/{name}',
auth: true, // require auth on all endpoints
})
export class SecureAgent extends BaseAgent {
// ...
}
// Or per-endpoint:
@endpoint({ get: "/admin", auth: true })
async adminOnly(principal: Principal): Promise<AdminData> {
// principal contains the authenticated user's identity
}When authentication is enabled, agent constructors and methods can optionally receive a Principal parameter containing information about the authenticated caller.
Phantom Agents
Endpoints can be served by phantom agents — ephemeral, stateless agents that are created for each request and discarded afterward. This is useful for gateway-like agents that dispatch to internal agents, allowing requests to be processed completely in parallel.
TypeScript
@agent({
mount: '/gateway/{name}',
phantomAgent: true,
})
export class Gateway extends BaseAgent {
// A new instance is created per request
}Deployments
To make the code-first routes accessible, a deployment section is needed in the application manifest (golem.yaml). This maps agents to domains per environment:
httpApi:
deployments:
local:
- domain: app-name.localhost:9006
agents:
Tasks: {}You can specify which agents to deploy to which (sub)domains, organized by environment (e.g. local, staging, prod).
Deploying the API
Once the deployment is configured in golem.yaml, deploy with:
golem app deployOpenAPI Specification
Golem automatically generates an OpenAPI specification from the code-first route definitions. Each deployment exposes an openapi.yaml endpoint:
curl http://app-name.localhost:9006/openapi.yamlThis returns a standard OpenAPI 3.0 specification describing all the deployed endpoints, including path parameters, request/response schemas, and more.
Troubleshooting
See the troubleshooting page for some common issues and their solutions.