Goal
- TypeScript controllers and models as the single source of truth for your API
- A valid swagger spec is generated from your controllers and models, including:
- Paths (e.g. GET /Users)
- Definitions based on TypeScript interfaces (models)
- Parameters/model properties marked as required or optional based on TypeScript (e.g. myProperty?: string is optional in the Swagger spec)
- jsDoc supported for object descriptions (most other metadata can be inferred from TypeScript types)
- Routes are generated for middleware of choice
- Express, Hapi, and Koa currently supported, other middleware can be supported using a simple handlebars template
- Validate request payloads
Philosophy
- Rely on TypeScript type annotations to generate API metadata if possible
- If regular type annotations aren't an appropriate way to express metadata, use decorators
- Use jsdoc for pure text metadata (e.g. endpoint descriptions)
- Minimize boilerplate
- Models are best represented by interfaces (pure data structures), but can also be represented by classes
How it works
Installation
npm install tsoa --save// ORnpm install lukeautry/tsoa#[VERSION]
Create Controllers
// controllers/usersController.ts ;;;
Create Models
// models/user.ts ;
Note that type aliases are only supported for string literal types like type status = 'Happy' | 'Sad'
Generate
From command line/npm script:
// generate swagger.json
tsoa swagger
// generate routes
tsoa routes
Override route template
Route templates are generated from predefined handlebar templates. You can override and define your own template to use by defining it in your tsoa.json configuration. Route paths are generated based on the middleware type you have defined.
{
"swagger": {
...
},
"routes": {
"entryFile": "...",
"routesDir": "...",
"middleware": "express",
"middlewareTemplate": "custom-template.ts"
...
}
}
Consume generated routes
;;;; // controllers need to be referenced in order to get crawled by the generator; ;app.usebodyParser.urlencoded;app.usebodyParser.json;app.usemethodOverride; RegisterRoutesapp; app.listen3000;
Get access to the request object of express in Controllers
To access the request object of express in a controller method use the @Request
-decorator:
// controllers/usersController.ts ;;;
Note that the parameter request
does not appear in your swagger definition file.
Likewise you can use the decorator @Inject
to mark a parameter as being injected manually and should be omitted in swagger generation.
In this case you should write your own custom template where you inject the needed objects/values in the method-call.
Dependency injection / IOC
By default all the controllers are created by the auto-generated routes template using an empty default constructor.
If you want to use dependency injection and let the DI-framework handle the creation of your controllers you can use inversifyJS.
To tell tsoa
to use your DI-container you have to reference your module exporting the DI-container in the config file (e.g. tsoa.json
):
The convention is that you have to name your inversify Container
iocContainer
and export it in the given module.
Note that as of 1.1.1 the path is now relative to the your current working directory like the other paths.
Here is some example code how to setup the container and your controller.
./inversify/ioc.ts
:
;; ; ;; ; ; ;
./contollers/fooController.ts
;;
Specify error response types for Swagger
@Response('400', 'Bad request')
@DefaultResponse<ErrorResponse>('Unexpected error')
@Get('Response')
public async getResponse(): Promise<TestModel> {
return new ModelService().getModel();
}
Authentication
Authentication is done using a middleware handler along with @Security('name', ['scopes'])
decorator in your controller.
First, define the security definitions for swagger, and also configure where the authentication middleware handler is. In this case, it is in the authentication.ts
file.
In the middleware, export the function based on which library (Express, Koa, Hapi) you are using. You only create 1 function to handle all authenticate types. The securityName
and scopes
come from the annotation you put above your controller function.
./authentication.ts
;; ; ; ;
./contollers/securityController.ts
;
Path Mapping
Per the TypeScript Handbook under module resolution:
Sometimes modules are not directly located under baseUrl. For instance, an import to a module "jquery" would be translated at runtime to "node_modules\jquery\dist\jquery.slim.min.js". Loaders use a mapping configuration to map module names to files at run-time, see RequireJs documentation and SystemJS documentation.
The TypeScript compiler supports the declaration of such mappings using "paths" property in tsconfig.json files. Here is an example for how to specify the "paths" property for jquery.
If you have a project that utilized this functionality, you can configure the internal generators to use the correct paths by providing a compilerOptions property to route configuration property in tsoa.json.
Use awesome Swagger tools
Now that you have a swagger spec (swagger.json), you can use all kinds of amazing tools that generate documentation, client SDKs, and more.
Command Line Interface
For information on the configuration object (tsoa.json), check out the following:
Swagger.json generation
Usage: tsoa swagger [options]
Options:
--configuration, -c tsoa configuration file; default is tsoa.json in the working directory [string]
--host API host [string]
--basePath Base API path [string]
Route generation
Usage: tsoa routes [options]
Options:
--configuration, -c tsoa configuration file; default is tsoa.json in the working directory [string]
--basePath Base API path [string]
Examples
An example project is available here
Also see example controllers in the tests