Appearance
Examples
Study after study shows that examples are a crucial part of learning new APIs (1, 2, 3). While certain issues, like type mismatches can be avoided by inferring examples from the JSON Schema (like the examples SwaggerUI automatically generates*), it's often a lot more intuitive if we provide certain examples ourselves.
* Which is limited as well, i.e. patterns will be ignored, and just sending the string "string" every time is somewhat suboptimal if that string actually carries meaning.
TIP
tsoa does not (yet) check your JSDoc examples. Incorrect examples will not break your compilation, because OpenAPI explicitly allows anything. You may also just want to demonstrate tsoa's validation 😏
We recommend using a linter (we love Spectral) to ensure your specifications aren't just correct, but also contain descriptions and correct examples.
WARNING
OpenAPI 2 only allows one example per model/property/parameter. If you defined more than one example in OpenAPI 2, tsoa will only apply first one as value. OpenAPI 3 examples is now supported!
Response examples
In order to provide an example response, tsoa offers a @Example()
Decorator.
TIP
Providing the type you're writing the example for as a type argument T
to
ts
@Example<T>(example: T)
is not necessary, but may help you catch bugs.
This decorator is used to specify a response for the default response, but you can add examples for other responses (@Response()
, used for additional responses, often caused by errors by providing them as the third argument as well.
Default response
ts
@Route("users")
export class UsersController extends Controller {
@Example<User>({
id: "52907745-7672-470e-a803-a2f8feb52944",
name: "tsoa user",
email: "hello@tsoa.com",
phoneNumbers: [],
status: "Happy",
})
@Get("{userId}")
public async getUser(
@Path() userId: UUID,
@Query() name: string
): Promise<User> {
return new UsersService().get(userId, name);
}
}
Additional Responses
ts
@Route("users")
export class UsersController extends Controller {
/**
* Add a new user. Remember that the demo API will not persist this data.
*
*/
@Post()
@SuccessResponse("201", "Created") // Custom success response
@Response<ValidateErrorJSON>(422, "Validation Failed", {
message: "Validation failed",
details: {
requestBody: {
message: "id is an excess property and therefore not allowed",
value: "52907745-7672-470e-a803-a2f8feb52944",
},
},
})
public async createUser(
@Body() requestBody: UserCreationParams
): Promise<void> {
this.setStatus(201); // set return status 201
new UsersService().create(requestBody);
return;
}
}
Parameter examples
WARNING
You may expect to see an example for a type reference (to a type alias, interface or a class) if you set one. However, since it'll be transformed to a reference ($ref) to the schema, the example must be ignored, since any properties that are placed next to $ref (OpenAPI's mechanism to link to the UserCreationParams schema) must be ignored.
For more info, check out the relevant parts of the OpenAPI Specification and JSON Schema Core
ts
@Route("users")
export class UsersController extends Controller {
/**
* @example userId "52907745-7672-470e-a803-a2f8feb52944"
* @example userId "e77ef155-bd12-46f0-8559-bf55f6dd4c63"
*/
@Get("{userId}")
public async getUser(
@Path() userId: UUID,
@Query() name: string
): Promise<User> {
return new UsersService().get(userId, name);
}
}
Model examples
WARNING
Both OpenAPI 2 and 3 supports only single example in model. If you use more than one example, it will only apply the first one.
ts
/**
* Stringified UUIDv4.
* See [RFC 4112](https://tools.ietf.org/html/rfc4122)
* @pattern [0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-4[0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}
* @example "52907745-7672-470e-a803-a2f8feb52944"
*/
export type UUID = string;
WARNING
Any example with object or array should be in correct JSON-format. Otherwise, tsoa will throws error while generating OAS.
ts
/**
* User objects allow you to associate actions performed in the system with the user that performed them.
* The User object contains common information across every user in the system regardless of status and role.
*
*
* @example {
* "id": "52907745-7672-470e-a803-a2f8feb52944",
* "name": "John Doe",
* "phoneNumbers": []
* }
*/
export interface User {
id: UUID;
/**
* The email the user used to register his account
*/
email?: string;
name: string;
status?: "Happy" | "Sad";
phoneNumbers: string[];
}
Property examples
WARNING
You may expect to see an example for the id
if you set one. However, since it'll be transformed to a reference to the UUID schema, the example must be ignored, since any properties that are placed next to $ref (OpenAPI's mechanism to link to the UUID schema) must be ignored.
For more info, check out the relevant parts of the OpenAPI Specification and JSON Schema Core
ts
export interface User {
id: UUID;
/**
* The email the user used to register his account
*/
email?: string;
name: string;
/**
* @example "Happy"
*/
status?: "Happy" | "Sad";
phoneNumbers: string[];
}