Skip to content

Response annotations

By default the success response is derived from the method’s return type and the verb’s statusCode, and 400/401/403 are added when they apply (details). Use the annotations here to override the success response or add others.

Overrides the success response’s status, description or body schema. Also the element type of the responses: list on verb annotations and of Responses.

@Target({TargetKind.method})
class Returns {
const Returns({
this.statusCode,
this.description,
this.contentType = 'application/json',
this.bodyType,
});
}

When to use: when the method returns a raw Response (so the generator cannot see the body type), or when you want a different status code or description in the document. For extra, non-success responses use ApiResponse.

Parameter Type Default Description
statusCode int? null Success status. When null, the verb’s statusCode is used. Overrides the runtime status too when the method returns a value or void.
description String? null Response description. Defaults to the reason phrase (OK, Created, …).
contentType String 'application/json' Currently not used; responses are documented as application/json.
bodyType Type? null Schema for the body. Only used when the method returns Response; otherwise the return type is used.

In a list (inline responses: or Responses) the first entry is the success response and each later entry with a statusCode is added as another response. Entries after the first without a statusCode are ignored. Standalone @Returns/@Responses annotations win over the inline responses: list; if several are stacked, their entries are combined in order.

Example

import 'package:gisila_doc/gisila_doc.dart';
@Get('/me')
@Returns(bodyType: UserResponse, description: 'The signed-in user')
Future<Response> me(Request request) async { /* ... */ }
@Post(
'/register',
summary: 'Register a new account',
body: BodyDoc(UserRegisterRequest),
responses: [
Returns(statusCode: 201, bodyType: UserResponse),
Returns(statusCode: 409, bodyType: ErrorResponse, description: 'Email taken'),
],
)
Future<Response> register(Request request) async { /* ... */ }

Adds one more response entry to an operation.

@Target({TargetKind.method})
class ApiResponse {
const ApiResponse(
this.statusCode, {
this.description,
this.contentType = 'application/json',
this.bodyType,
});
}

When to use: to document error and alternative responses (404, 409, 422, …). Stack as many as you need. Declaring 400, 401 or 403 yourself replaces the automatic entry for that code.

Parameter Type Default Description
statusCode int required Status code. Positional.
description String? null Defaults to the reason phrase (Not Found, Conflict, …; Status <code> for others).
contentType String 'application/json' Currently not used; a body is documented as application/json.
bodyType Type? null Body schema. Without it the response has no content.

Example

@Get('/{id}', summary: 'Fetch a user')
@ApiResponse(404, description: 'User not found')
@ApiResponse(410, description: 'User was deleted', bodyType: Tombstone)
Future<User> getUser(String id, UserService users) => users.getById(id);

The automatic 400/401/403 entries use gisila’s error body, errorEnvelopeSchema. ApiResponse takes a Dart type, not a schema map, so to document the same body on your own error responses point bodyType at a class with the same shape (error: {status, message, code, details}).

Declares a list of Returns entries in one annotation.

@Target({TargetKind.method})
class Responses {
const Responses(this.responses);
final List<Returns> responses;
}

When to use: when the inline responses: list makes the verb annotation hard to read, or when you want to reuse a const response list across routes. Behaves exactly like the inline list.

Example

const crudResponses = Responses([
Returns(statusCode: 200, bodyType: Product),
Returns(statusCode: 404, description: 'No such product'),
]);
@Get('/{id}')
@crudResponses
Future<Response> getProduct(String id, Request request) async { /* ... */ }

Intended to add an extra tag to a single operation.

@Target({TargetKind.method})
class Tag {
const Tag(this.name, [this.description]);
}
@Get('/stats', tags: ['Reporting'])
Future<Stats> stats(StatsService s) => s.current();
// at startup
spec.putTag('Reporting', description: 'Aggregated numbers');