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.