Swagger with typescript based Express.js (Node) application.

saurabh pathare
4 min readJan 9, 2021

API documentation is very essential for development of REST APIs and their integration with consumers. In this article we will use typescript based Express.js(Node) project, Swagger UI Express, TSOA.

Prerequisites

  • Node (>v14.15.4)
  • Typescript(>v4.1.3)

GitHub Link

Create Express.js Project

If you have an existing Express.js project then you can skip below steps but make sure you have installed required packages before jumping to the next step.

  1. Create folder for your new project.
mkdir swagger-typescript-express
cd swagger-typescript-express

2. Initialize a package.json file.

npm init -y

3. Install required packages.

npm install express
npm install --save-dev typescript
npm install --save-dev @types/node @types/express

4. Createtsconfig.json file into root folder.

This file instructs Typescript how to compile (transpile) Typescript code into plain JavaScript.

{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"moduleResolution": "node",
"outDir": "./dist",
"esModuleInterop": true,
"resolveJsonModule": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}

5. Create a folder named src. In this folder, create a file named main.ts. Open the file and add the following code in it.

import express from "express";
const app = express();
const port = 8080; // default port to listen

// define a route handler for the default home page
app.get("/",( req, res) => {
res.send( "Hello world!" );
} );

// start the Express server
app.listen( port, () => {
console.log( `server started at http://localhost:${ port }` );
} );

6. Update package.json to instruct npm on how to run your application. Change the main property value pointing to dist/main.js, add a start script (tsc && node.) and run it to check whether your application is running or not (http://localhost:8080).

"main": "dist/src/main.js",
"scripts": {
"start": "tsc && node ."
},

Add TSOA (TypeScript OpenAPI)

This library uses TypeScript type annotations or decorators to generate routes for middleware (express.js) and Swagger configuration file required for Swagger UI Express.

  1. Install TSOA and depended packages.
npm install tsoa --save-dev
npm install --save-dev @types/node @types/express
npm install swagger-ui-express
npm install --save-dev @types/swagger-ui-express
npm install body-parser

Note: No need to install @types/node and @types/express if done in first step.

2. Add config filetsoa.json into root folder with following minimal content.

{
"entryFile":"./src/main.ts",
"noImplicitAdditionalProperties":"throw-on-extras",
"controllerPathGlobs":[
"src/controller/*"
],
"spec":{
"outputDirectory":"./dist",
"specVersion":3
},
"routes":{
"routesDir":"./dist"
}
}

3. Write a sample Controller and Model

Create a folder named src/controller. In this folder, create a file named controller.ts. Open the file and add the following code in it. I have added a sample CRUD operations and demonstrated usage of associated terms like header, request body, query param, path variable and Input validation.

import { 
Controller,
Route,
Get,
Path,
Query,
Post,
Header,
Body,
Response
} from 'tsoa';
import User from '../model/user';
@Route("users")
export class UsersController extends Controller {
/**
* API to get User by userId
* @param userId sample for path param
*/
@Get("/{userId}")
public async getUser(
@Path() userId: number
): Promise<User> {
return { userId: userId, name: "abc", email: "abc@gmail.com" };
}
/**
* API to create User
* @param requestBody sample for request body
* @minLength mail 3 must be > 3 letters
* @param mail sample for query param
* @param someOptionalHeader sample for Header and it is optional
*/
@Response('201', 'created')
@Post("/")
public async createUser(
@Body() requestBody: User,
@Query() mail: string,
@Header('some-header') someOptionalHeader?: string
): Promise<User> {
/*Business Logic*/
this.setStatus(201);
return { userId: 1, name: "abc", email: mail };
}
}

Then create a folder named src/model. In this folder, create a file named user.ts. Open the file and add the following code in it.

export default interface User {
userId: number
name: string
email: string
}

4. Update main.ts , to register generated routes and configure Swagger UI Express.

import bodyParser from 'body-parser';
import express from "express";
import swaggerUi from "swagger-ui-express";
import { RegisterRoutes } from '../dist/routes';
import swaggerDocument from '../dist/swagger.json';
const app = express();
const port = 8080; // default port to listen
// define a route handler for the default home page
app.get("/", (req, res) => {
res.send("Hello world!");
});
//Parse incoming request bodies in a middleware before your handlers
app.use(bodyParser.json())
// This will register generated routes
RegisterRoutes(app);
// Provide generated swagger.json as input to swagger UI.
app.use('/api-docs',swaggerUi.serve,swaggerUi.setup(swaggerDocument))
// start the Express server
app.listen(port, () => {
console.log(`server started at http://localhost:${port}`);
});

5. Update package.json to add start:swagger script.

This command will generate swagger.json file (tsoa swagger) and routes (tsoa routes) in ./dist folder. Then it will transpile the code (tsc) and start the application (node.)

"scripts": {
"start": "tsc && node .",
"start:swagger": "tsoa swagger && tsoa routes && tsc && node ."
}

6. Now you can start your application using command npm run start:swagger, you can open your application http://localhost:8080/api-docs/

--

--