Creating API Documentation with Swagger on NodeJS

Introduction

Swagger is a popular, simple, and user-friendly tool for creating APIs. Most backend developers, regardless of the programming languages they use, are familiar with Swagger. This article will guide you through creating API documentation using Swagger on Node.js (specifically integrated with the Express framework). This is handy when you want to provide API documentation in a professional UI format for stakeholders involved in integration.

Restful API

REST stands for Representational State Transfer. It is an architectural style that defines a set of constraints for creating web services. RESTful APIs provide a simple and flexible way to access web services without complex processing.

Common HTTP Methods in RESTful APIs:

- GET: Used to read (retrieve) a representation of a resource. It returns data in XML or JSON format.

- POST: Creates new resources or subordinates to existing ones.

- PUT: Updates existing resources or creates new ones if the client chooses the resource ID.

- PATCH: Partially modifies resources, describing changes rather than sending the entire resource.

- DELETE: Removes a resource.


Building API and API Documentation with Swagger

In this example, we'll use Node.js, Express, and Swagger. First, let's set up a Node.js project and install the necessary packages:

yarn add express swagger-jsdoc swagger-ui-express
yarn add -D @types/swagger-jsdoc @types/swagger-ui-express


Create a file named swagger.ts with Swagger document configuration as follows:

import * as swaggerJsdoc from 'swagger-jsdoc'
import * as swaggerUi from 'swagger-ui-express'

const options = {
definition: {
openapi: '3.0.0',
info: {
title: 'Employee API',
description: 'Example of CRUD API ',
version: '1.0.0',
},
},
apis: ['./router/*.ts'], // path to routers
}

const swaggerSpec = swaggerJsdoc(options)

export function swaggerDocs(app, port) {
app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec))
app.get('/docs.json', (req, res) => {
res.setHeader('Content-Type', 'application/json')
res.send(swaggerSpec)
})
}


Next up is the index.ts file for integrating Express and Swagger.

import * as express from 'express'
import router from './router'
import {swaggerDocs} from './swagger'

const app = express()
const port = 3000
app
.use(express.json())
.use(router)
.listen(port, () => {
console.log(`Listening at http://localhost:${port}`)
swaggerDocs(app, port)
})


To set up the API routers, I'll create a file named router.ts and define the API documentation right above the routers, identified by the keyword @openapi.

The APIs will include 4 methods: GET, POST, PUT, DELETE.

import * as express from 'express'
import {addEmployeeHandler, deleteEmployeeHandler, editEmployeeHandler, getEmployeesHandler} from './controller'

const router = express.Router()

/**
* @openapi
* '/api/employees':
* get:
* tags:
* - Employee
* summary: Get all employee
* responses:
* 200:
* description: Success
* content:
* application/json:
* schema:
* type: array
* items:
* type: object
* properties:
* id:
* type: number
* name:
* type: string
* 400:
* description: Bad request
*/
router.get('/api/employees', getEmployeesHandler)

/**
* @openapi
* '/api/employee':
* post:
* tags:
* - Employee
* summary: Create a employee
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - id
* - name
* properties:
* id:
* type: number
* name:
* type: string
* responses:
* 201:
* description: Created
* 409:
* description: Conflict
* 404:
* description: Not Found
*/
router.post('/api/employee', addEmployeeHandler)

/**
* @openapi
* '/api/employee':
* put:
* tags:
* - Employee
* summary: Modify a employee
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - id
* - name
* properties:
* id:
* type: number
* name:
* type: string
* responses:
* 200:
* description: Modified
* 400:
* description: Bad Request
* 404:
* description: Not Found
*/
router.put('/api/employee', editEmployeeHandler)

/**
* @openapi
* '/api/employee/{id}':
* delete:
* tags:
* - Employee
* summary: Remove employee by id
* parameters:
* - name: id
* in: path
* description: The unique id of the employee
* required: true
* responses:
* 200:
* description: Removed
* 400:
* description: Bad request
* 404:
* description: Not Found
*/
router.delete('/api/employee/:id', deleteEmployeeHandler)

export default router


I'll also provide an additional file named controller.ts, implemented in a simple way to handle API requests.

import {Request, Response} from 'express'

let employees = [
{id: 1, name: 'Name 1'},
{id: 2, name: 'Name 2'},
]

export function getEmployeesHandler(req: Request, res: Response) {
res.status(200).json(employees)
}

export function addEmployeeHandler(req: Request, res: Response) {
if (employees.find(employee => employee.id === req.body.id)) {
res.status(409).json('Employee id must be unique')
} else {
employees.push(req.body)
res.status(200).json(employees)
}
}

export function deleteEmployeeHandler(req: Request, res: Response) {
const index = employees.findIndex(employee => employee.id === +req?.params?.id)
if (index >= 0) {
employees.splice(index, 1)
res.status(200).json(employees)
} else {
res.status(400).send()
}
}

export function editEmployeeHandler(req: Request, res: Response) {
const index = employees.findIndex(employee => employee.id == req.body.id)
if (index >= 0) {
employees.splice(index, 1, req.body)
res.status(200).json(employees)
} else {
res.status(400).send()
}
}


After successfully starting the project, you can access the page http://localhost:3000/docs to view the API documentation in UI format generated by Swagger.

restful api swagger

Conclusion

API Documentation is one of the crucial documents that back-end developers provide to stakeholders to facilitate integration (such as front-end teams).

Due to the popularity and convenience of Restful API and Swagger, it's an indispensable tool for creating API documentation in a simple, professional, and consistent UI format.

Comments

Popular posts from this blog

Kubernetes Practice Series

NodeJS Practice Series

Docker Practice Series

React Practice Series

Sitemap

Explaining Async/Await in JavaScript in 10 Minutes

Deploying a NodeJS Server on Google Kubernetes Engine

What is react-query? Why should we use react-query?

A Handy Guide to Using Dynamic Import in JavaScript

Create API Gateway with fast-gateway