Skip to content

21 Swagger Docs

DodaTech 4 min read

title: Swagger Documentation for Node.js REST APIs weight: 31 date: 2026-06-28 lastmod: 2026-06-28 description: Generate Swagger/OpenAPI documentation for Node.js REST APIs using swagger-jsdoc and swagger-ui-express with JSDoc annotations and automatic schema generation. tags: [api-development, nodejs]


Swagger documentation for Node.js REST APIs uses swagger-jsdoc to parse JSDoc annotations into OpenAPI specifications and swagger-ui-express to serve interactive API documentation with try-it-out functionality.

```mermaid
flowchart TD
  A[JSDoc Comments] --> B[swagger-jsdoc]
  B --> C[OpenAPI Spec]
  C --> D[swagger-ui-express]
  D --> E[Interactive Docs]
  E --> F[/api-docs]
  A --> G[Route definitions]
  A --> H[Schema definitions]
  A --> I[Response examples]
  style A fill:#e1f5fe
  style C fill:#fff9c4
  style E fill:#c8e6c9

Document routes inline using JSDoc comments above route handlers. Define schemas separately for reusability. The swagger-jsdoc package scans your code for these comments and generates the OpenAPI JSON, which swagger-ui-express serves as interactive HTML documentation.

Think of JSDoc annotations like cooking recipe cards attached to each dish in a restaurant kitchen. The chef (developer) writes the recipe, and the menu (Swagger UI) presents it to customers in a readable format.

Example: Swagger Setup

const swaggerJsdoc = require('swagger-jsdoc');
const swaggerUi = require('swagger-ui-express');

const options = {
  definition: {
    openapi: '3.0.3',
    info: {
      title: 'My API',
      version: '1.0.0',
      description: 'REST API documentation'
    },
    servers: [
      { url: 'http://localhost:3000', description: 'Development' }
    ],
    components: {
      securitySchemes: {
        bearerAuth: {
          type: 'http',
          scheme: 'bearer',
          bearerFormat: 'JWT'
        }
      },
      schemas: {
        User: {
          type: 'object',
          required: ['name', 'email'],
          properties: {
            id: { type: 'string', description: 'User ID' },
            name: { type: 'string', description: 'Full name' },
            email: { type: 'string', format: 'email' },
            role: { type: 'string', enum: ['user', 'admin'] }
          }
        },
        Error: {
          type: 'object',
          properties: {
            status: { type: 'string' },
            error: {
              type: 'object',
              properties: {
                code: { type: 'string' },
                message: { type: 'string' }
              }
            }
          }
        }
      }
    }
  },
  apis: ['./src/routes/*.js']
};

const swaggerSpec = swaggerJsdoc(options);
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
app.get('/api-docs.json', (req, res) => res.json(swaggerSpec));

Example: JSDoc Route Annotations

/**
 * @swagger
 * /api/users:
 *   get:
 *     summary: List all users
 *     tags: [Users]
 *     security:
 *       - bearerAuth: []
 *     parameters:
 *       - in: query
 *         name: page
 *         schema:
 *           type: integer
 *         description: Page number
 *       - in: query
 *         name: limit
 *         schema:
 *           type: integer
 *         description: Items per page
 *     responses:
 *       200:
 *         description: User list
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 status:
 *                   type: string
 *                 data:
 *                   type: array
 *                   items:
 *                     $ref: '#/components/schemas/User'
 */
router.get('/users', authenticate, userController.listUsers);

/**
 * @swagger
 * /api/users/{id}:
 *   get:
 *     summary: Get user by ID
 *     tags: [Users]
 *     parameters:
 *       - in: path
 *         name: id
 *         required: true
 *         schema:
 *           type: string
 *     responses:
 *       200:
 *         description: User details
 *       404:
 *         description: User not found
 */
router.get('/users/:id', authenticate, userController.getUser);

Example: Request Body Annotation

/**
 * @swagger
 * /api/users:
 *   post:
 *     summary: Create a new user
 *     tags: [Users]
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             required:
 *               - name
 *               - email
 *               - password
 *             properties:
 *               name:
 *                 type: string
 *               email:
 *                 type: string
 *                 format: email
 *               password:
 *                 type: string
 *                 format: password
 *               role:
 *                 type: string
 *                 enum: [user, admin]
 *     responses:
 *       201:
 *         description: User created
 *       400:
 *         description: Validation error
 *         content:
 *           application/json:
 *             schema:
 *               $ref: '#/components/schemas/Error'
 */
router.post('/users', validate(userSchema), userController.createUser);

Common Mistakes

  1. Documentation out of sync with code — Update JSDoc annotations whenever route handlers change. Outdated documentation is worse than no documentation.
  2. Missing response examples — Every response should include an example. Developers understand examples faster than schema definitions.
  3. Not documenting error responses — Document every error code and response format so clients can handle failures correctly.
  4. Overly complex schemas — Keep schemas simple and reusable. Use $ref to compose complex schemas from smaller, reusable components.
  5. Not including authentication in documentation — Every protected endpoint should show the required security scheme. Add the lock icon in Swagger UI.

Practice Questions

  1. How do you generate OpenAPI specs from JSDoc comments?
  2. What is the purpose of $ref in OpenAPI schemas?
  3. How do you document authentication requirements?
  4. How do you serve Swagger UI in Express?
  5. Challenge: Document a complete CRUD API for products using swagger-jsdoc. Include all endpoints, request bodies, response schemas, error responses, authentication, and examples. Verify the spec with the Swagger Editor validator.

FAQ

What is the difference between swagger-jsdoc and swagger-autogen?

swagger-jsdoc scans JSDoc comments. swagger-autogen analyzes route code directly. swagger-jsdoc gives you more control over documentation.

Should I deploy Swagger UI in production?

It depends on your security policy. Swagger UI exposes your API structure. Some companies deploy it internally or behind authentication.

How do I organize large OpenAPI specs?

Split the spec into multiple files: main spec, schemas, paths, and examples. Use $ref to compose them. Keep each component file focused.

What is the best way to document enum values?

Define enums in the schema: role: { type: string, enum: [user, admin, moderator] }. Swagger UI renders them as dropdown menus.

How do I test my OpenAPI spec?

Use the Swagger Editor (editor.swagger.io) to validate your spec. Use swagger-cli validate to automate validation in CI/CD.

Mini Project

Generate complete Swagger documentation for a blog API with posts, comments, users, and tags. Include: all CRUD endpoints with annotations, reusable schemas, authentication security scheme, request/response examples, error response documentation, and a custom theme for Swagger UI.

What's Next

Now learn about deployment with Docker in Building REST APIs with Node.js.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro