Skip to main content
Controllers group related route handlers under a common URL prefix. In nestrs, a controller is a plain Rust struct annotated with #[controller]. Route handlers live in an impl block annotated with #[routes]. When the module builds, nestrs registers every handler in that impl block as an Axum route under the controller’s prefix.

Defining a controller

The prefix argument sets the base path for every route in the controller. Paths are joined with each handler’s path, so prefix = "/api" + #[get("/")] produces GET /api/.

Optional attributes

Use the #[version] attribute separately to apply a version to an entire controller struct:

Registering routes with #[routes]

The #[routes] macro annotates an impl block and takes a state argument that names the injected service type. nestrs uses this to build an Axum router with the correct State type:
state must be a type registered in the same module’s providers list. nestrs resolves it from the ProviderRegistry and injects it as Axum State.

HTTP method macros

nestrs provides a macro for every HTTP method: Each macro takes the route path as its argument. The path is appended to the controller’s prefix.

Route examples

Basic GET and POST

Path parameters

Use Axum’s Path extractor. Parameters are declared in the route path with a colon prefix (:id):

Query parameters

Use Axum’s Query extractor with a deserializable struct:

JSON request bodies

Use Axum’s Json extractor for unvalidated JSON, or ValidatedBody to run validator constraints automatically:

Response customization

Custom HTTP status code

Custom response headers

Redirects

Versioning a single route

You can version a single route within a controller using #[ver] while leaving other routes at the controller’s default version:

Registering the controller in a module

Controllers must be listed in the controllers field of their module:
A single controller can only be registered in one module. Shared logic belongs in a provider (service), not a controller.