Skip to content

Route annotations

All annotations on this page come from package:gisila_doc/gisila_doc.dart. They replace gisila’s annotations of the same names, which that import hides.

Marks a class as a controller. The builder generates an attachToApp extension for it.

@Target({TargetKind.classType})
class Controller {
const Controller([this.path = '', this.tags = const <String>[]]);
final String path;
final List<String> tags;
}

When to use: on every class whose methods should become routes and OpenAPI operations. Use the path for a common prefix (/users) and tags to group the controller’s operations in Swagger UI and Redoc.

Parameter Type Default Description
path String '' Prefix joined to every method path. Positional.
tags List<String> [] Tags added to every operation in the class and registered at the top level of the document with spec.putTag. Positional.

Class-level gisila annotations are honoured too: @UseRouteConfig, @RequireAuth, @Permissions, @AnyPermission, @Roles and @UseMiddleware.

Example

import 'package:gisila_doc/gisila_doc.dart';
part 'users_controller.g.dart';
@Controller('/users', ['Users'])
@RequireAuth()
class UsersController {
@Get('/me', summary: 'Current user')
Future<User> me(RequestContext ctx, UserService users) =>
users.getById(ctx.principal!.id);
}

See also: How generation works, Generated code.

Base class of every verb annotation. Usable directly for a verb that has no dedicated class.

@Target({TargetKind.method})
class Route {
const Route(
this.method,
this.path, {
this.summary,
this.description,
this.operationId,
this.deprecated = false,
this.tags = const <String>[],
this.statusCode = 200,
this.body,
this.responses,
this.config,
});
}

When to use: almost never directly; prefer Get, Post and the other subclasses. @Route('GET', '/x') behaves exactly like @Get('/x').

Parameter Type Default Description
method String required HTTP verb, e.g. 'GET'.
path String required Path relative to the controller. Use {name} for path parameters.
summary String? null Operation summary.
description String? null Operation description (Markdown is rendered by the docs UIs).
operationId String? null Operation operationId. Omitted from the document when not set; set it if you generate clients, since generators use it for method names.
deprecated bool false Emits deprecated: true. The route still works.
tags List<String> [] Extra tags for this operation, added to the controller’s tags.
statusCode int 200 Success status when the method returns a value or void. Ignored at runtime when the method returns a Response, but still used in the document.
body BodyDoc? null Inline request body documentation. See BodyDoc. A standalone @BodyDoc on the same method wins, and a typed body or form parameter wins over both.
responses List<Returns>? null Inline response list. The first entry overrides the success response; the rest are added. Standalone @Returns/@Responses on the same method win. See Returns.
config RouteConfig? null Per-route gisila configuration (rate limit, timeout, body size, content types, CORS, middleware, permissions), merged on top of AppConfig.defaultRouteConfig and the class @UseRouteConfig. See the framework docs.

See also: Response annotations.

GET route.

class Get extends Route {
const Get(String path, {String? summary, String? description, String? operationId,
bool deprecated = false, List<String> tags = const <String>[], int statusCode = 200,
BodyDoc? body, List<Returns>? responses, RouteConfig? config});
}

When to use: reads. Primitive parameters not in the path become query parameters.

Example

@Get(
'/',
summary: 'List users',
description: 'Returns a (paginated) list of all known users.',
)
Future<List<User>> listUsers(UserService users, {int? limit, int? offset}) =>
users.list(limit: limit, offset: offset);

@Get('/') under a controller prefix is served at both /users/ and /users.

POST route. Same parameters as Get, but statusCode defaults to 201.

class Post extends Route {
const Post(String path, {..., int statusCode = 201, ...});
}

When to use: creating resources. The first non-primitive, non-service parameter (or a Form) becomes the request body.

Example

@Post(
'/',
summary: 'Create a user',
config: RouteConfig(rateLimit: RateLimitConfig(requestsPerMinute: 60)),
)
Future<User> createUser(CreateUserForm form, UserService users) => users.create(
name: form.name.value!,
email: form.email.value!,
age: form.age.value,
);

PUT route. Same parameters as Get; statusCode defaults to 200.

When to use: full replacement of a resource.

@Put('/{id}', summary: 'Replace a user')
Future<User> replace(String id, UpdateUser body, UserService users) =>
users.replace(id, body);

PATCH route. Same parameters as Get; statusCode defaults to 200.

When to use: partial updates.

@Patch('/{id}', summary: 'Rename a user')
Future<User> rename(String id, RenameUser body, UserService users) =>
users.rename(id, body.name);

DELETE route. Same parameters as Get, but statusCode defaults to 204.

When to use: deletes. Return Future<void> to send an empty 204.

@Delete('/{id}', summary: 'Delete a user')
Future<void> deleteUser(String id, UserService users) => users.delete(id);

HEAD route. Takes path, summary, description, operationId, deprecated, tags, responses and config; no statusCode (always 200) and no body.

When to use: existence or metadata checks without a body, typically returning a Response.

@Head('/{id}')
Future<Response> exists(String id, UserService users) async =>
(await users.exists(id)) ? Response.ok(null) : Response.notFound(null);

OPTIONS route. Same parameters as Head.

When to use: rarely; gisila’s CORS middleware already answers preflight requests. Use it only for a custom OPTIONS response.

gisila_doc re-exports these from gisila; they are documented in the framework section:

Symbol Purpose
RouteConfig Per-route configuration passed as config:.
UseRouteConfig Class-level RouteConfig applied to every route of a controller.
RequireAuth, Public, Permissions, AnyPermission, Roles Guards. The builder reads them to add security, 401/403 and x-gisila-guards to the operation.
UseMiddleware Named middleware for a class or method.