How to generate an OpenAPI/Swagger spec with tsoa
In this tutorial, we’ll learn how to create an OpenAPI schema using tsoa (TypeScript OpenAPI)
Tip
If you want to follow along, you can use the tsoa Speakeasy Bar example repository
How to generate an OpenAPI/Swagger spec with tsoa
To generate an OpenAPI spec using tsoa generateSpec function. tsoa saves the spec as swagger.json by default, but we can customize the base filename using the configuration option specFileBaseName.
Generating an OpenAPI Spec Using the tsoa CLI
Generate an OpenAPI spec
By default, tsoa will use the configuration from the tsoa.json file with your generated routes and metadata to generate an OpenAPI spec.
In our example app, the relevant tsoa.json config is as follows:
This configures tsoa to output the generated OpenAPI spec in the build directory and to use OpenAPI version 3.
Programmatically Generate an OpenAPI Spec Using tsoa
To generate an OpenAPI spec using the OpenAPI internal generator functions generateSpec and call this function by passing a spec config of type ExtendedSpecConfig from tsoa.
CAUTION
The recommended way to generate an OpenAPI Spec is via the CLI as tsoa
warns generateSpec and ExtendedSpecConfig can change in minor or patch
releases of tsoa. The example below is illustrative and not included in the
example app.
Add the code above to a TypeScript file and run it to generate an OpenAPI spec using the custom configuration defined in specOptions.
Supported OpenAPI Versions
As of August 2023, tsoa can generate OpenAPI version 2 and version 3 specifications. Speakeasy supports OpenAPI version 3 and version 3.1. To use Speakeasy, make sure to configure tsoa to generate OpenAPI v3.
To set the OpenAPI version, add spec.specVersion=3 to your tsoa.json configuration file:
How tsoa Generates OpenAPI info
When generating an OpenAPI spec, tsoa tries to guess your API’s title, description, and contact details based on values in your project package.json file.
Tip
Values in tsoa.json take precedence over those in package.json when
configured.
Set OpenAPI info in package.json
Take this snippet from our example app’s package.json file:
By default, tsoa will generate the following spec based on the values above:
tsoa uses the package author as the contact person by default, extracting the author’s email address and optional URL from the person format defined by npm
Set OpenAPI Info Using tsoa Configuration
To manually configure your OpenAPI info section, configure tsoa using the tsoa.json file:
After adding this custom configuration, tsoa will use these values instead of those from package.json when generating a spec.
Update tsoa to Generate OpenAPI Component Schemas
Let’s see how we can help tsoa generate separate and reusable component schemas for a request body.
Consider the following drink model:
We’d like to write a controller that updates the name and price fields. The controller should take both fields as body parameters.
We’ll start with the example controller below. Note how the body parameters drinkName and price are defined by passing the @BodyProp decorator to the controller function multiple times.
This would generate inline parameters without documentation for the UpdateDrink operation in OpenAPI, as shown in the snippet below:
While perfectly valid, this schema is not reusable and excludes the documentation and examples from our model definition.
We recommend picking fields from the model interface directly and exporting a new interface. We could use the TypeScript utility types Pick and Partial to pick the name and price fields and make both optional:
In our controller, we can now use DrinkUpdateParams as follows:
Customizing OpenAPI operationId Using tsoa
When generating an OpenAPI spec, tsoa adds an operationId to each operation.
We can customize the operationId in three ways:
- Using the
@OperationIddecorator. - Using the default tsoa
operationIdgenerator. - Creating a custom
operationIdtemplate.
Using the @OperationId Decorator
The most straightforward way to customize the operationId is to add the @OperationId decorator to each operation.
In the example below, the custom operationId is updateDrinkNameOrPrice:
Using the Default tsoa operationId Generator
If a controller method is not decorated with the OperationId decorator, tsoa generates the operationId by converting the method name to title case using the following Handlebars template:
Creating a Custom operationId Template
To create a custom operationId for all operations without the @OperationId decorator, tsoa allows us to specify a Handlebars template in tsoa.json. tsoa adds two helpers to Handlebars: replace and titleCase. The method object and controller name get passed to the template as method and controllerName.
The following custom operationId template prepends the controller name and removes underscores from the method name:
Add OpenAPI Tags to tsoa Methods
At Speakeasy, whether you’re building a big application or only have a handful of operations, we recommend adding tags to all operations so you can group them by tag in generated SDK code and documentation.
Add Tags to Operations Using Decorators
tsoa provides the @Tags() decorator for controllers and controller methods. The decorator accepts one or more strings as input.
Contrary to the illustrative example above, we recommend adding a single tag per method or controller to ensure that the generated SDK is split into logical units.
Add Metadata to Tags
To add metadata to tags, add a tags object to your tsoa.json:
Add Speakeasy Extensions to Methods
Sometimes OpenAPI’s vocabulary is insufficient for your generation needs. For these situations, Speakeasy provides a set of OpenAPI extensions. For example, you may want to give an SDK method a name different from the OperationId. To cover this use case, we provide an x-speakeasy-name-override extension.
To add these custom extensions to your OpenAPI spec, you can make use of tsoa’s @Extension() decorator:
Add Retries to Your SDK With x-speakeasy-retries
Speakeasy can generate SDKs that follow custom rules for retrying failed requests. For instance, if your server fails to return a response within a specified time, you may want your users to retry their request without clobbering your server.
Add retries to SDKs generated by Speakeasy by adding a top-level x-speakeasy-retries schema to your OpenAPI spec. You can also override the retry strategy per operation by adding x-speakeasy-retries.
Adding Global Retries
To add a top-level retries extension to your OpenAPI spec, add a new spec schema to the spec configuration in tsoa.json:
Adding Retries per Method
To add retries to individual methods, use the tsoa @Extension decorator.
In the example below, we add x-speakeasy-retries to the updateDrink method:
How To Generate an SDK Based on Your OpenAPI Spec
Once you have an OpenAPI spec, use Speakeasy to generate an SDK by calling the following in the terminal:
Follow the onscreen prompts to provide the necessary configuration details for your new SDK such as the name, schema location and output path. Enter build/swagger.json when prompted for the OpenAPI document location and select TypeScript when prompted for which language you would like to generate.
You can generate SDKs using Speakeasy when your API definition in tsoa changes. Many Speakeasy users add SDK generation to their CI workflows to ensure their SDKs are always up to date.
Summary
This tutorial explored different configurations and customizations available for the OpenAPI specification generation using tsoa. We’ve also learned how to assign and customize OpenAPI operationId and OpenAPI tags to our tsoa methods. Finally, we demonstrated how to add retries to your SDKs using x-speakeasy-retries. With this knowledge, you should now be able to leverage tsoa, OpenAPI, and Speakeasy more effectively for your API.
Take a look at our Speakeasy Bar (tsoa) example repository
Last updated on