How to add a Swagger UI to a TS ExpressJS App using Tsoa
How to add a Swagger UI to a TS ExpressJS App using Tsoa
You can add a decorator-based UI like this to an Express App by adding a few packages and configuring your endpoints.
I have a full working example code repo right here.
1. Add tsoa and swagger-ui-express to your app:
npm install tsoa swagger-ui-express body-parser express
npm install --save-dev typescript @types/swagger-ui-express @types/body-parser @types/express
2. Rewrite your routes to work with tsoa. Here is some example code taken from A.K. Bejaoui:
// src/users/usersController.ts
export interface User {
id: number;
email: string;
name: string;
status?: "Happy" | "Sad";
phoneNumbers: string[];
}export type UserCreationParams = Pick<User, "email" | "name" | "phoneNumbers">;
public get(id: number, name?: string): User {
return {
id,
email: "
name: name ?? "Jane Doe",
status: "Happy",
phoneNumbers: [],
};
}
public create(userCreationParams: UserCreationParams): User {
return {
id: Math.floor(Math.random() * 10000),
status: "Happy",
...userCreationParams,
};
}
}export class UsersService {public get(id: number, name?: string): User {return {id,email: " [email protected] ",name: name ?? "Jane Doe",status: "Happy",phoneNumbers: [],};public create(userCreationParams: UserCreationParams): User {return {id: Math.floor(Math.random() * 10000),status: "Happy",...userCreationParams,};
import {
Body, Controller, Get, Path, Post, Query, Route, SuccessResponse,
} from "tsoa";
export class UsersController extends Controller {
public async getUser(
): Promise<User> {
return new UsersService().get(userId, name);
}
public async createUser(
): Promise<void> {
this.setStatus(201); // set return status 201
new UsersService().create(requestBody);
return;
}
}@Route ("users")export class UsersController extends Controller { @Get ("{userId}")public async getUser( @Path () userId: number, @Query () name?: string): Promise {return new UsersService().get(userId, name); @SuccessResponse ("201", "Created") @Post ()public async createUser( @Body () requestBody: UserCreationParams): Promise {this.setStatus(201); // set return status 201new UsersService().create(requestBody);return;
3. Set up your express app to load the code that we will generate with tsoa:
// src/app.ts
import express from “express”;
import bodyParser from “body-parser”;import { RegisterRoutes } from “./routes”;
import * as swaggerJson from “./swagger.json”;
import * as swaggerUI from “swagger-ui-express”;
export const app = express();app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());RegisterRoutes(app);
app.use([“/openapi”, “/docs”, “/swagger”], swaggerUI.serve, swaggerUI.setup(swaggerJson));
const port = process.env.PORT || 3000;
console.log(`Example app listening at
);app.listen(port, () =>console.log(`Example app listening at http://localhost:${port}` );
4. Configure tsoa with tsoa.json:
{
"entryFile": "src/app.ts",
"noImplicitAdditionalProperties": "throw-on-extras",
"controllerPathGlobs": ["src/**/*Controller.ts"],
"spec": {
"outputDirectory": "src",
"specVersion": 3
},
"routes": {
"routesDir": "src"
}
}
5. Also ensure that decorators are enabled in tsconfig.json:
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "build",
"moduleResolution": "node",
"resolveJsonModule": true,
"baseUrl": ".",
"esModuleInterop": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
6. Build the project by generating code with tsoa, then compiling with tsc:
npx tsoa spec-and-routes && npx tsc
This will generate src/routes.ts
and src/swagger.json
, and will put the finished app in the build
directory (or wherever compilerOptions.outDir points in tsconfig.json)
You can then run the app:
node build/app.js
And see the Swagger UI at http://localhost:3000/swagger
Note, this tutorial is largely a simplification of this one.