@talosjs/controller component is the HTTP/WebSocket handler layer. A controller is a class with a single index method, bound to a route by a @Route decorator. When a request matches the route, the framework constructs a context (request data, response builder, logger, cache, user, locale, and route metadata) and calls index(context). The handler reads what it needs from context and returns a response. Generics carry your params, payload, queries, and response shapes end to end, so the context is fully typed.
The model
Every controller implementsIController as a single typed index(context) handler. There is no base class to extend and no boilerplate. IController<T> and ContextType<T> thread your params, payload, queries, and response types through the whole handler, and the handler receives a lot in that context: the parsed request, a response builder, the logger, cache, rate limiter, locale, authenticated user, headers, files, IP, host, and the matched route metadata.
Routing is decorator-bound. @Route.get, @Route.post, @Route.socket, and the rest tie a class to a path, method, version, validation schema, and roles in one place. The index method may return an IResponse directly or a Promise<IResponse>; both work. The same controller shape covers HTTP and WebSocket, with socket controllers using a context that adds a channel API.
How it works
A request flows through routing into the matched controller and back out as a response. The handler never constructs the context; the framework builds it, then callsindex.
The
index signature is the whole contract:
ContextConfigType describes the shape you bind to a route. response is always present, while params, payload, and queries come from the request config and are optional. ContextType<T> is the object passed to index. Its most-used members:
Usage
A controller is a class with oneindex method, decorated with a @Route method matching the HTTP verb. Define a route type once and pass it to both the decorator config and ContextType<T> so the context is fully typed.
@Route object exposes one decorator per HTTP method — get, post, put, patch, delete, options, head — plus socket for WebSocket controllers. Each takes the route path and a config:
A controller with URL params reads them through
context.request.params() (validated by the decorator’s params):
context.request.payload():
Socket controllers
WebSocket controllers share the same one-method shape but are bound with@Route.socket and use ContextType from @talosjs/socket, which adds a channel API (channel.send, channel.publish, channel.subscribe, channel.close, channel.ws). The CLI scaffolds either variant; pass --is-socket=true for the socket template.
Keeping controllers clean
Keep controllers thin. Validate and shape the request, hand the work to an injected service, and return the response; no business logic lives inindex. Define one route type and reuse it, passing the same type to the @Route config and to ContextType<T> so params, payload, queries, and response stay in sync. Include only what the route needs: params for path segments, payload for post, put, and patch, queries for list and search endpoints, and response every time.
Read request data through context.request.params(), .payload(), and .queries() so the decorator’s Assert schemas run before your code does. Set roles to the lowest role that satisfies the endpoint, since access is hierarchical and a role also grants the ones it inherits. Return responses through the context.response builder rather than assembling raw HTTP responses by hand. Finally, treat cache, rateLimiter, permission, and user as optional: they may be absent, so guard with ?. and have a fallback.
CLI command
Scaffold a controller, its route type, and a test file with the generator. It writes the class tomodules/<module>/src/controllers/<Name>Controller.ts, registers it in the module, and installs @talosjs/controller if it is missing.
The generated class is a typed stub: a route type, a
@Route decorator with empty Assert schemas, and an index that returns an empty JSON response, ready for you to fill in:
Use with Claude and Codex
The generator ships a matchingcontroller:create skill. It runs the scaffold and then guides your AI agent through completing the controller: filling in the route type, validation schemas, roles, and the index handler, and delegating logic to a service. Initialize the skills once for your agent:
- Claude
- Codex
Prompt
controller:create run with an inferred name, route, and method, then implements the index handler against the user’s profile service.