Parameter and body annotations
Most parameters need no annotation: the generator infers the location from the name and type
(see parameter classification).
Use the annotations on this page to rename a parameter, add a description, force a location, or
document inputs for handlers that read the raw Request themselves.
Binds a method parameter to a path placeholder.
@Target({TargetKind.parameter})class Path { const Path({this.name, this.description, this.example}); final String? name; final String? description; final Object? example;}When to use: when the Dart parameter name differs from the {placeholder}, or to add a
description. A parameter whose name already matches a placeholder is a path parameter without
it.
| Parameter | Type | Default | Description |
|---|---|---|---|
name |
String? |
Dart parameter name | Placeholder name, without braces. |
description |
String? |
null |
Parameter description in the document. |
example |
Object? |
null |
Accepted but currently not emitted by the generator. |
The value is parsed with coerce<T>() (String, int, double, num, bool, DateTime)
and is always required: true. A value that does not parse is a 400.
Example
import 'package:gisila_doc/gisila_doc.dart';
@Get('/{userId}/posts')Future<List<Post>> posts( @Path(name: 'userId', description: 'Author id') int id, PostService posts,) => posts.byAuthor(id);Binds a method parameter to a query-string key.
@Target({TargetKind.parameter})class Query { const Query({this.name, this.description, this.example});}When to use: to rename a query key (?page_size= to pageSize) or describe it. Primitive
parameters that are not path placeholders are query parameters without it.
| Parameter | Type | Default | Description |
|---|---|---|---|
name |
String? |
Dart parameter name | Query key. |
description |
String? |
null |
Parameter description. |
example |
Object? |
null |
Accepted but currently not emitted. |
The parameter is required when its type is non-nullable and it is not optional. An empty value
(?page=) counts as missing for anything but String. Dart default values are not applied, so
declare optional query parameters nullable and apply defaults in the method body.
Example
@Get('/')Future<List<User>> list( UserService users, { @Query(name: 'page_size', description: 'Rows per page') int? pageSize,}) => users.list(limit: pageSize);Header
Section titled “Header”Binds a method parameter to a request header.
@Target({TargetKind.parameter})class Header { const Header({this.name, this.description});}When to use: whenever you want a header as a parameter; headers are never inferred.
| Parameter | Type | Default | Description |
|---|---|---|---|
name |
String? |
Dart parameter name | Header name. Looked up lower-cased. |
description |
String? |
null |
Parameter description. |
The generated code assigns the raw header string with no parsing, so declare the parameter as
String?. It is documented as required when the Dart type is non-nullable and not optional.
Example
@Post('/webhooks')Future<void> hook( WebhookEvent event, @Header(name: 'X-Signature', description: 'HMAC of the body') String? signature,) async { /* ... */ }Marks a method parameter as the JSON request body.
@Target({TargetKind.parameter})class Body { const Body({ this.contentType = 'application/json', this.required = true, this.description, });}When to use: when the body parameter would otherwise be classified differently, for example
a Map<String, dynamic> you want as the body even though another parameter came first. The
first unannotated non-primitive parameter is already treated as the body.
| Parameter | Type | Default | Description |
|---|---|---|---|
contentType |
String |
'application/json' |
Currently not used by the generator; the body is always read and documented as JSON. |
required |
bool |
true |
Currently not used; requiredness comes from the parameter (required unless optional or nullable). |
description |
String? |
null |
Currently not emitted. |
To document a body with a description or another content type, use BodyDoc.
Example
@Put('/{id}/settings')Future<void> saveSettings(String id, @Body() Map<String, dynamic> settings) async { /* ... */}QueryDoc
Section titled “QueryDoc”Documents a query parameter that the handler reads itself from request.url.queryParameters.
@Target({TargetKind.method})class QueryDoc { const QueryDoc( this.name, { this.type = String, this.required = false, this.description, });}When to use: with the raw-Request style, where the method takes a Request and parses
inputs itself, so the generator cannot see them. Stack one per parameter. It only affects the
document; nothing is parsed or validated for you.
| Parameter | Type | Default | Description |
|---|---|---|---|
name |
String |
required | Query key. |
type |
Type |
String |
Dart type used to derive the schema. |
required |
bool |
false |
Parameter required. |
description |
String? |
null |
Parameter description. |
Example
@Get('/products')@QueryDoc('offset', type: int)@QueryDoc('limit', type: int)@QueryDoc('search', description: 'Matches name or SKU')Future<Response> listProducts(Request request) async { final q = request.url.queryParameters; // ... return jsonResponse(body: await products.search(q['search']));}BodyDoc
Section titled “BodyDoc”Documents the request body schema for a route.
@Target({TargetKind.method})class BodyDoc { const BodyDoc( this.type, { this.required = true, this.description, this.contentType = 'application/json', });}When to use: when the method does not take a typed body or Form parameter (it reads the
Request itself) but you still want the body documented, or when you need a description or a
non-JSON content type in the document. Prefer the inline form, @Post('/x', body: BodyDoc(T)).
A typed body or form parameter takes precedence over BodyDoc; a standalone @BodyDoc takes
precedence over the inline body:.
| Parameter | Type | Default | Description |
|---|---|---|---|
type |
Type |
required | Class whose schema describes the body. |
required |
bool |
true |
requestBody.required. |
description |
String? |
null |
requestBody.description. |
contentType |
String |
'application/json' |
Media type key under content. |
Example
@Post( '/login', summary: 'Log in', body: BodyDoc(LoginRequest, description: 'Login credentials'), responses: [Returns(statusCode: 200, bodyType: TokenResponse)],)Future<Response> login(Request request) async { final json = await readJsonBody(request) as Map<String, dynamic>; // ...}See also: Describe request and response models, How schemas are derived.