We started the Express.js journey with a simple CRUD Express.js app that has a bunch of APIs. Though returned dummy data. Then we added MySQL support that made the app more usable. But still, one big piece is missing. And that’s API documentation in Swagger and Swagger UI. In this article, we go through how to add Swagger to an Express.js app in five minutes.
By contrast to Java Spring Boot that adding Swagger and Swagger UI is a piece of cake, thanks to huge sets of annotations. The process is quite different in Express.js and other languages like PHP. We need to handcraft the documentation, generate JSON or YAML file and then add it to the application.
Don’t panic! It is not difficult at all. We go through each step in this article.
Adding swagger-ui-express library
There are numerous libraries available for Swagger UI. Based on my experiments the best is <a href="https://www.npmjs.com/package/swagger-ui-express">swagger-ui-express</a>
. It’s super easy to use. Hence, I highly recommend it.
To add swagger-ui-express
to the project, just run,
$ npm install --save swagger-ui-express
Creating the Swagger documentation
By far this is the most timeconsuming step. We have to handcraft the documentation. For that, we leverage on Swagger Editor. We start by modifying the example and adding the stuff related to our User APIs.
There’s nothing much for me to explain here. It’s all trial and error. Just make sure to add the correct data type. It is not difficult at all. It’s just timeconsuming.
The final result looks like this:
openapi: 3.0.1
info:
title: User API
description: 'This is a sample User API created with Express.js. You can find more about it [here](https://github.com/kasramp/sample-rest-with-expressjs).'
contact:
email: [email protected]
license:
name: MIT
url: https://opensource.org/licenses/MIT
version: 1.0.0
tags:
- name: user
description: Operations about user
paths:
/api/v1/users:
get:
tags:
- user
summary: Get list of users
operationId: getUsers
responses:
200:
description: Successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/User'
type: string
post:
tags:
- user
summary: Create a user
operationId: createUser
requestBody:
description: Created user object
content:
'application/json':
schema:
$ref: '#/components/schemas/UserDto'
required: true
responses:
201:
description: User created successfully
content:
application/json:
schema:
$ref: '#/components/schemas/User'
400:
description: Invalid payload supplied
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/v1/users/{id}:
get:
tags:
- user
summary: Get a user by id
operationId: getUserById
parameters:
- name: id
in: path
description: 'The id of a user'
required: true
schema:
type: integer
responses:
200:
description: Successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/User'
400:
description: Invalid id supplied
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
404:
description: User not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
put:
tags:
- user
summary: Update a user
operationId: updateUser
parameters:
- name: id
in: path
description: id of a user to update
required: true
schema:
type: integer
requestBody:
description: Updated user object
content:
'application/json':
schema:
$ref: '#/components/schemas/UserDto'
required: true
responses:
200:
description: Successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/User'
400:
description: Invalid payload supplied
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
404:
description: User not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
tags:
- user
summary: Delete a user
operationId: deleteUserById
parameters:
- name: id
in: path
description: The id of user to be deleted
required: true
schema:
type: integer
responses:
204:
description: User deleted successfully
400:
description: Invalid id supplied
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
UserDto:
type: object
properties:
firstName:
type: string
lastName:
type: string
age:
type: integer
format: int64
User:
type: object
properties:
id:
type: integer
format: int64
firstName:
type: string
lastName:
type: string
age:
type: integer
format: int64
Error:
type: object
properties:
error:
type: string
ApiResponse:
type: object
properties:
code:
type: integer
format: int32
type:
type: string
message:
type: string
But we need the json
version. We can generate that via Swagger Editor too. Just go to File
and click on Convert and save as JSON
.
{
"openapi": "3.0.1",
"info": {
"title": "User API",
"description": "This is a sample User API created with Express.js. You can find more about it [here](https://github.com/kasramp/sample-rest-with-expressjs).",
"contact": {
"email": "[email protected]"
},
"license": {
"name": "MIT",
"url": "https://opensource.org/licenses/MIT"
},
"version": "1.0.0"
},
"tags": [
{
"name": "user",
"description": "Operations about user"
}
],
"paths": {
"/api/v1/users": {
"get": {
"tags": [
"user"
],
"summary": "Get list of users",
"operationId": "getUsers",
"responses": {
"200": {
"description": "Successful operation",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User",
"type": "string"
}
}
}
}
}
},
"post": {
"tags": [
"user"
],
"summary": "Create a user",
"operationId": "createUser",
"requestBody": {
"description": "Created user object",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserDto"
}
}
},
"required": true
},
"responses": {
"201": {
"description": "User created successfully",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
}
},
"400": {
"description": "Invalid payload supplied",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
},
"/api/v1/users/{id}": {
"get": {
"tags": [
"user"
],
"summary": "Get a user by id",
"operationId": "getUserById",
"parameters": [
{
"name": "id",
"in": "path",
"description": "The id of a user",
"required": true,
"schema": {
"type": "integer"
}
}
],
"responses": {
"200": {
"description": "Successful operation",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
}
},
"400": {
"description": "Invalid id supplied",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "User not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
},
"put": {
"tags": [
"user"
],
"summary": "Update a user",
"operationId": "updateUser",
"parameters": [
{
"name": "id",
"in": "path",
"description": "id of a user to update",
"required": true,
"schema": {
"type": "integer"
}
}
],
"requestBody": {
"description": "Updated user object",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserDto"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful operation",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
}
},
"400": {
"description": "Invalid payload supplied",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "User not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
},
"delete": {
"tags": [
"user"
],
"summary": "Delete a user",
"operationId": "deleteUserById",
"parameters": [
{
"name": "id",
"in": "path",
"description": "The id of user to be deleted",
"required": true,
"schema": {
"type": "integer"
}
}
],
"responses": {
"204": {
"description": "User deleted successfully"
},
"400": {
"description": "Invalid id supplied",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"UserDto": {
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"age": {
"type": "integer",
"format": "int64"
}
}
},
"User": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"age": {
"type": "integer",
"format": "int64"
}
}
},
"Error": {
"type": "object",
"properties": {
"error": {
"type": "string"
}
}
},
"ApiResponse": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"type": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
}
}
}
Now let’s create a directory called swagger
in the application root and place both YAML and JSON versions.
Use swagger.json in the project
Now that we have the documentation ready, we just need to glue things together. Head to app.js
and add the following lines of code,
import swaggerUi from "swagger-ui-express";
import swaggerDocument from "./swagger/swagger.json";
// removed for brevity
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocument));
As you can see we just added only three lines of code. The first line imports the swagger-ui-express
library. The second line points to the Swagger documentation that we created in the previous step. And the last line creates a route to serve the document.
Now if you run, npm run start
and type http://localhost:8090/api-docs
you should be able to see the Swagger UI and interact with the APIs,
The complete example is available on GitHub at the link below,
https://github.com/kasramp/sample-rest-with-expressjs
That’s all. Hope it didn’t take more than five minutes to add Swagger to the Express.js 😀
Inline/featured images credits
- Keyboard and laptop image by Paul Esch-Laurent on Unsplash