index(context) method. A route and its controller are two halves of one unit: the decorator describes the contract (path, method, what input is valid, who is allowed in), and the controller supplies the behavior.
Because every route is declared on the class that serves it, the definition lives next to the code that runs, and the same configuration object drives parameter parsing, validation, access control, and named URL generation.
What the route decorator buys you
The route lives on the controller it serves, so there’s no central route file drifting out of sync with its handlers. Path params, query strings, and request bodies are validated with@talosjs/validation schemas before your controller runs, so index receives typed, trusted data. Roles, permission classes, and env/ip/host restrictions are part of the same definition, which keeps “who can reach this” visible right where the route is declared.
Routes are referenced by name rather than by a hardcoded path: every route has one, and you generate URLs from it with router.generate(...) instead of scattering stringly-typed paths across the codebase. The same decorator family declares HTTP and WebSocket endpoints, so socket routes follow the same naming and validation conventions as HTTP ones.
How it works
The router holds a map of paths to route configurations. EachRoute.* decorator builds a route config from the path and your options, marks the HTTP method (or isSocket: true for sockets), attaches the controller class, and registers it with the container as a singleton. At request time the framework matches the path and method, validates the input against the route’s schemas, enforces any access rules, and invokes the matched controller’s index(context).
The decorator takes the path as its first argument and the config object as its second:
Defining a route
ImportRoute and decorate a controller class. The method decorator name maps to the HTTP method: Route.get, Route.post, Route.put, Route.delete, Route.patch, Route.options, and Route.head. The controller implements IController and exposes an index(context) method that returns a response.
Configuration options
Every option exceptpath and method (which come from the decorator) is passed in the config object.
The decorator supplies
path, method, isSocket, and controller
automatically — you never set those in the config object.Route naming
Every route has a uniquename following the namespace.resource.action convention, for example api.users.list or admin.products.create. Names must be unique across the whole app; registering two routes with the same name throws a RouterException. The name is what you pass to router.generate(...) and what the router uses for lookups.
Valid namespaces:
api, client, admin, public, auth, webhook, internal, external, system, metrics, docs
The middle resource segment names the thing the route acts on (users, products, users.orders), and the final action segment names the operation (list, show, create, update, delete, search, and many more).
Path parameters
Dynamic path segments are written with a leading colon, like:id. Each declared parameter should have a schema in params; after validation the values are available on context.params.
/api/users/:userId/orders/:orderId, and each is matched into context.params by name.
Query validation
Provide aqueries schema to validate and coerce the query string. The schema handles defaults and optional keys, so the controller reads ready-to-use values from context.queries.
Payload validation
For routes that accept a request body, declare apayload schema. The body is validated before index runs, and the parsed value is on context.payload.
Response validation
Declare aresponse schema to describe the shape index returns. Unlike params, queries, and payload, the response schema is not a runtime gate on the request. It documents the route’s output contract and drives type derivation and codegen, so generated clients and API docs stay in sync with what the controller actually sends back.
@talosjs/validation construct used for input, the response shape lives in the route contract alongside its inputs. Describe it once on the decorator and the generated types and documentation follow.
WebSocket routes
Route.socket(path, config) declares a WebSocket endpoint. It takes the same config as the HTTP decorators (the method is ignored and isSocket is set to true), but the controller’s context comes from @talosjs/socket and exposes a channel for subscribing and publishing.
Generating URLs
Look routes up by name and build their URL withrouter.generate(name, params). Path parameters are interpolated from the params object; missing required parameters throw a RouterException.
Access control
Routes can declare who is allowed to reach them. These checks run before the controller, so an unauthorized request never reachesindex.
For role-based access, list the roles permitted to call the route:
permission at a permission class that decides per request:
env, ip, and host lists:
Conventions worth following
Name every route asnamespace.resource.action so names stay predictable and router.generate calls read clearly. Declare params, queries, and payload schemas at the boundary, so index works with trusted, typed data instead of re-checking input by hand, and use router.generate(name, params) wherever you need a route URL rather than hardcoding one.
Keep one route per controller: a controller’s index serves a single route, so split distinct operations into distinct controllers. Put roles, permission, and env/ip/host rules on the route itself so the contract states who may reach it. Set version deliberately so clients and generated docs can track route revisions.
Scaffolding
Generate a controller and its route together with the CLI rather than wiring one by hand:index(context) method consumes the validated request.