5 min read
Adding API Documentation with Swagger to Your Node.js API
This tutorial builds on our rate-limited API by adding comprehensive API documentation using Swagger/OpenAPI. We'll implement interactive documentation that helps developers understand and test your API endpoints.
Prerequisites
- Completed Parts 1-4 of the tutorial
- Basic understanding of REST API concepts
- Node.js and npm installed
Project Setup
Install the required dependencies:
npm install swagger-ui-express swagger-jsdoc yaml
Updated Project Structure
Add these new files to your project:
books-api/
├── src/
│ ├── config/
│ │ ├── database.js
│ │ ├── auth.js
│ │ ├── rateLimiter.js
│ │ └── swagger.js
│ ├── docs/
│ │ ├── swagger.yaml
│ │ ├── components.yaml
│ │ ├── paths/
│ │ │ ├── auth.yaml
│ │ │ └── books.yaml
│ │ └── schemas/
│ │ ├── Book.yaml
│ │ └── User.yaml
│ └── server.js
Environment Setup
Update your .env
file:
API_VERSION=1.0.0
API_TITLE=Books API
API_DESCRIPTION=RESTful API for managing books
API_SERVER_URL=http://localhost:3000
Swagger Configuration
Create src/config/swagger.js
:
const swaggerJsdoc = require('swagger-jsdoc');
const yaml = require('yaml');
const fs = require('fs');
const path = require('path');
// Read individual YAML files
const readYamlFile = (filePath) => {
const fileContents = fs.readFileSync(filePath, 'utf8');
return yaml.parse(fileContents);
};
// Swagger definition
const swaggerDefinition = {
openapi: '3.0.0',
info: {
title: process.env.API_TITLE,
version: process.env.API_VERSION,
description: process.env.API_DESCRIPTION,
license: {
name: 'MIT',
url: 'https://opensource.org/licenses/MIT',
},
contact: {
name: 'API Support',
email: 'support@example.com',
},
},
servers: [
{
url: process.env.API_SERVER_URL,
description: 'Development server',
},
],
components: {
securitySchemes: {
BearerAuth: {
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
},
},
schemas: {
Book: readYamlFile(path.join(__dirname, '../docs/schemas/Book.yaml')),
User: readYamlFile(path.join(__dirname, '../docs/schemas/User.yaml')),
},
},
};
// Swagger options
const options = {
swaggerDefinition,
apis: [
'./src/routes/*.js',
'./src/docs/paths/*.yaml'
],
};
const swaggerSpec = swaggerJsdoc(options);
module.exports = swaggerSpec;
Schema Definitions
Create src/docs/schemas/Book.yaml
:
type: object
properties:
_id:
type: string
format: objectId
description: The auto-generated id of the book
title:
type: string
description: The title of the book
author:
type: string
description: The author of the book
isbn:
type: string
description: ISBN number of the book
publishedDate:
type: string
format: date
description: Publication date of the book
genre:
type: string
description: Genre of the book
description:
type: string
description: Brief description of the book
required:
- title
- author
- isbn
Create src/docs/schemas/User.yaml
:
type: object
properties:
_id:
type: string
format: objectId
description: The auto-generated id of the user
email:
type: string
format: email
description: User's email address
name:
type: string
description: User's full name
role:
type: string
enum: [user, editor, admin]
description: User's role in the system
createdAt:
type: string
format: date-time
description: Account creation timestamp
required:
- email
- name
- role
API Path Documentation
Create src/docs/paths/books.yaml
:
/api/books:
get:
tags:
- Books
summary: Get all books
description: Retrieve a list of all books with optional filtering
parameters:
- in: query
name: genre
schema:
type: string
description: Filter books by genre
- in: query
name: author
schema:
type: string
description: Filter books by author
responses:
200:
description: Successful operation
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Book'
429:
description: Too many requests
500:
description: Server error
post:
tags:
- Books
summary: Add a new book
description: Add a new book to the database
security:
- BearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Book'
responses:
201:
description: Book created successfully
400:
description: Invalid input
401:
description: Unauthorized
429:
description: Too many requests
Create src/docs/paths/auth.yaml
:
/api/auth/login:
post:
tags:
- Authentication
summary: User login
description: Authenticate user and receive JWT token
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
email:
type: string
format: email
password:
type: string
format: password
required:
- email
- password
responses:
200:
description: Login successful
content:
application/json:
schema:
type: object
properties:
token:
type: string
user:
$ref: '#/components/schemas/User'
401:
description: Invalid credentials
429:
description: Too many login attempts
Route Documentation
Update your route files to include JSDoc comments. Example for src/routes/books.js
:
const express = require('express');
const router = express.Router();
/**
* @swagger
* tags:
* name: Books
* description: Book management endpoints
*/
/**
* @swagger
* /api/books/{id}:
* get:
* tags: [Books]
* summary: Get a book by ID
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* description: Book ID
* responses:
* 200:
* description: Success
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/Book'
* 404:
* description: Book not found
*/
router.get('/:id', getBook);
// Other routes...
Updated Server File
Update src/server.js
:
const express = require('express');
const swaggerUi = require('swagger-ui-express');
const swaggerSpec = require('./config/swagger');
const { basicRateLimiter } = require('./middleware/rateLimiter');
const app = express();
// Swagger UI setup
app.use(
'/api-docs',
swaggerUi.serve,
swaggerUi.setup(swaggerSpec, {
explorer: true,
customSiteTitle: 'Books API Documentation',
customCss: '.swagger-ui .topbar { display: none }',
swaggerOptions: {
docExpansion: 'none',
persistAuthorization: true,
filter: true,
},
})
);
// Rate limit the documentation
app.use('/api-docs', basicRateLimiter);
// Existing middleware and routes...
Custom Documentation Customization
Create a custom documentation template:
const customOptions = {
customCssUrl: '/custom-swagger.css',
customJs: '/custom-swagger.js',
customfavIcon: '/favicon.ico',
};
// Custom CSS for documentation
app.get('/custom-swagger.css', (req, res) => {
res.sendFile(path.join(__dirname, 'docs/styles/swagger.css'));
});
Documentation Security
Implement documentation access control:
const docsAuthMiddleware = (req, res, next) => {
const apiKey = req.headers['x-api-key'];
if (process.env.NODE_ENV === 'production' && apiKey !== process.env.DOCS_API_KEY) {
return res.status(401).json({ error: 'Unauthorized access to documentation' });
}
next();
};
app.use('/api-docs', docsAuthMiddleware);
Testing Documentation
Test your API documentation using these curl commands:
# Get documentation JSON
curl http://localhost:3000/api-docs.json
# Test documentation with API key
curl -H "X-API-KEY: your_api_key" http://localhost:3000/api-docs
Best Practices Implemented
Organization
- Modular documentation structure
- Separate schema definitions
- Route-specific documentation files
- Environment-based configuration
Security
- Protected documentation access
- Rate-limited documentation endpoints
- Environment-specific settings
- Authentication examples
User Experience
- Interactive API testing
- Clear parameter descriptions
- Request/response examples
- Error documentation
Maintenance
- Version control
- Easy updates
- Consistent formatting
- Reusable components
Next Steps
To enhance your API further:
Conclusion
You now have comprehensive API documentation that:
- Helps developers understand your API
- Provides interactive testing
- Maintains security
- Scales with your API
- Follows OpenAPI standards
Remember to:
- Keep documentation updated
- Test documentation regularly
- Gather user feedback
- Monitor documentation usage
- Update examples as needed
The next tutorial will cover implementing automated testing for your API endpoints.
Related Posts
• 5 min read
APIs (Application Programming Interfaces) are the backbone of modern digital applications. They allow different software systems to communicate, exchange data, and collaborate seamlessly. As businesse...
• 4 min read
In today’s interconnected digital world, APIs (Application Programming Interfaces) are the backbone of communication between different software applications. From mobile apps to cloud services, APIs e...
• 5 min read
In the modern digital ecosystem, APIs (Application Programming Interfaces) serve as the backbone of connectivity. Whether you're building microservices, enabling integrations, or crafting data pipelin...