Course:Node.js & Express/
Lesson

You've built a beautiful RESTWhat is rest?An architectural style for web APIs where URLs represent resources (nouns) and HTTP methods (GET, POST, PUT, DELETE) represent actions on those resources. APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses.. The endpoints work perfectly, validation is solid, error handling is graceful. But here's the problem: nobody knows how to use it. Without documentation, your API is like a library with no catalog, the information exists, but it's impossible to find.

Think of API documentation as the user manual for your backend. It tells frontend developers what endpoints exist, what parameters they accept, and what responses they return. Good documentation turns integration from a guessing game into a straightforward process.

Why OpenAPIWhat is openapi?A standard format for describing REST APIs - their endpoints, parameters, and response shapes. Tools can generate documentation and client libraries from it automatically.?

OpenAPI (formerly Swagger) is the most widely adopted standard for describing RESTWhat is rest?An architectural style for web APIs where URLs represent resources (nouns) and HTTP methods (GET, POST, PUT, DELETE) represent actions on those resources. APIs. It's language-agnostic, human-readable, and machine-parseable. The specification lives as a JSONWhat is json?A text format for exchanging data between systems. It uses key-value pairs and arrays, and every programming language can read and write it. or YAMLWhat is yaml?A human-readable text format used for configuration files, including Docker Compose and GitHub Actions workflows. file that describes your entire APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses. surface.

With an OpenAPI spec, you can:

  • Generate interactive documentation that developers can test against
  • Create SDKWhat is sdk?A pre-built library from a service provider that wraps their API into convenient functions you call in your code instead of writing raw HTTP requests. clients in multiple languages automatically
  • Validate that your implementation matches the specification
  • MockWhat is mock?A fake replacement for a real dependency in tests that records how it was called so you can verify interactions. APIs for frontend development before the backend is ready

The spec vs the tools
OpenAPI is the specification format. Swagger is the set of tools (UI, Codegen, Editor) built around it. People often use the terms interchangeably, but OpenAPI is the standard, Swagger is the tooling.
02

Setting up Swagger in Express

Install the necessary packages:

npm install swagger-ui-express swagger-jsdoc

Configure Swagger in your Express app:

import swaggerUi from 'swagger-ui-express';
import swaggerJSDoc from 'swagger-jsdoc';

const swaggerOptions = {
  definition: {
    openapi: '3.0.0',
    info: {
      title: 'My API',
      version: '1.0.0',
      description: 'A sample API demonstrating OpenAPI documentation',
      contact: {
        name: 'API Support',
        email: 'support@example.com'
      }
    },
    servers: [
      {
        url: 'http://localhost:3000/api',
        description: 'Development server'
      },
      {
        url: 'https://api.example.com',
        description: 'Production server'
      }
    ]
  },
  // Files containing OpenAPI annotations
  apis: ['./routes/*.js', './controllers/*.js', './schemas/*.js']
};

const swaggerSpec = swaggerJSDoc(swaggerOptions);

// Serve interactive documentation
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));

// Also expose the raw JSON spec
app.get('/api-docs.json', (req, res) => {
  res.setHeader('Content-Type', 'application/json');
  res.send(swaggerSpec);
});

Now visit http://localhost:3000/api-docs and you'll see an interactive documentation page where you can browse endpoints and even make test requests.

03

Documenting endpoints with JSDoc

The magic happens when you annotate your route handlers with special JSDoc comments. swagger-jsdoc scans these comments and builds the OpenAPIWhat is openapi?A standard format for describing REST APIs - their endpoints, parameters, and response shapes. Tools can generate documentation and client libraries from it automatically. specification automatically.

GET endpointWhat is endpoint?A specific URL path on a server that handles a particular type of request, like GET /api/users. example

/**
 * @swagger
 * /users:
 *   get:
 *     summary: Get all users
 *     description: Returns a paginated list of users with optional filtering
 *     tags: [Users]
 *     parameters:
 *       - in: query
 *         name: page
 *         schema:
 *           type: integer
 *           default: 1
 *         description: Page number for pagination
 *       - in: query
 *         name: limit
 *         schema:
 *           type: integer
 *           default: 20
 *           maximum: 100
 *         description: Number of items per page
 *       - in: query
 *         name: search
 *         schema:
 *           type: string
 *         description: Search term to filter users by name or email
 *     responses:
 *       200:
 *         description: List of users retrieved successfully
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 status:
 *                   type: string
 *                   example: success
 *                 data:
 *                   type: array
 *                   items:
 *                     $ref: '#/components/schemas/User'
 *                 meta:
 *                   type: object
 *                   properties:
 *                     pagination:
 *                       type: object
 *                       properties:
 *                         page:
 *                           type: integer
 *                         total:
 *                           type: integer
 *       401:
 *         description: Unauthorized - Invalid or missing token
 *       500:
 *         description: Server error
 */
app.get('/users', getUsers);

POST endpoint with request body

/**
 * @swagger
 * /users:
 *   post:
 *     summary: Create a new user
 *     description: Creates a user account with email and password
 *     tags: [Users]
 *     requestBody:
 *       required: true
 *       description: User creation data
 *       content:
 *         application/json:
 *           schema:
 *             $ref: '#/components/schemas/CreateUser'
 *           examples:
 *             newUser:
 *               summary: Example user creation
 *               value:
 *                 name: "John Doe"
 *                 email: "john@example.com"
 *                 password: "securePassword123"
 *     responses:
 *       201:
 *         description: User created successfully
 *         content:
 *           application/json:
 *             schema:
 *               $ref: '#/components/schemas/User'
 *       400:
 *         description: Invalid input data
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 status:
 *                   type: string
 *                 message:
 *                   type: string
 *                 errors:
 *                   type: array
 *                   items:
 *                     type: object
 *       409:
 *         description: Email already registered
 */
app.post('/users', validate(CreateUserSchema), createUser);
The $ref syntax
$ref: '#/components/schemas/User' references a schema defined elsewhere in your documentation. This keeps your docs DRY (Don't Repeat Yourself), define the User schema once, reference it everywhere.
04

Defining reusable schemas

Instead of defining response structures inline, create reusable components:

/**
 * @swagger
 * components:
 *   schemas:
 *     User:
 *       type: object
 *       required:
 *         - id
 *         - email
 *         - name
 *       properties:
 *         id:
 *           type: integer
 *           description: Unique identifier
 *           example: 1
 *         email:
 *           type: string
 *           format: email
 *           description: User's email address
 *           example: "user@example.com"
 *         name:
 *           type: string
 *           description: User's display name
 *           example: "John Doe"
 *           minLength: 2
 *           maxLength: 50
 *         role:
 *           type: string
 *           enum: [user, admin, moderator]
 *           default: user
 *           description: User's permission level
 *         createdAt:
 *           type: string
 *           format: date-time
 *           description: Account creation timestamp
 *         avatar:
 *           type: string
 *           format: uri
 *           nullable: true
 *           description: URL to user's avatar image
 *     
 *     CreateUser:
 *       type: object
 *       required:
 *         - email
 *         - name
 *         - password
 *       properties:
 *         email:
 *           type: string
 *           format: email
 *           example: "newuser@example.com"
 *         name:
 *           type: string
 *           minLength: 2
 *           maxLength: 50
 *           example: "Jane Smith"
 *         password:
 *           type: string
 *           format: password
 *           minLength: 8
 *           description: Must contain uppercase, lowercase, and number
 *         age:
 *           type: integer
 *           minimum: 0
 *           maximum: 150
 *           description: Optional user age
 *     
 *     Error:
 *       type: object
 *       properties:
 *         status:
 *           type: string
 *           example: error
 *         message:
 *           type: string
 *           example: "User not found"
 *         code:
 *           type: string
 *           example: "USER_NOT_FOUND"
 *   
 *   securitySchemes:
 *     BearerAuth:
 *       type: http
 *       scheme: bearer
 *       bearerFormat: JWT
 *       description: Enter your JWT token in the format: Bearer {token}
 */

Store this in a separate file (like schemas/swagger.js) and include it in your apis array. The schemas defined here can be referenced from any endpointWhat is endpoint?A specific URL path on a server that handles a particular type of request, like GET /api/users. documentation.

05

AuthenticationWhat is authentication?Verifying who a user is, typically through credentials like a password or token. in documentation

APIs often require authentication. Document this clearly so developers know how to authenticate:

/**
 * @swagger
 * /users/profile:
 *   get:
 *     summary: Get current user profile
 *     description: Returns the profile of the authenticated user
 *     tags: [Users]
 *     security:
 *       - BearerAuth: []
 *     responses:
 *       200:
 *         description: User profile retrieved successfully
 *         content:
 *           application/json:
 *             schema:
 *               $ref: '#/components/schemas/User'
 *       401:
 *         description: Missing or invalid authentication token
 *       403:
 *         description: Token valid but user not found
 */
app.get('/users/profile', requireAuth, getProfile);

The security field tells Swagger UI to show an "Authorize" button where developers can enter their JWTWhat is jwt?JSON Web Token - a self-contained, signed token that carries user data (like user ID and role). The server can verify it without a database lookup. tokenWhat is token?The smallest unit of text an LLM processes - roughly three-quarters of a word. API pricing is based on how many tokens you use.. The token is then included in all subsequent "Try it out" requests.

06

Alternative approaches

Manual YAMLWhat is yaml?A human-readable text format used for configuration files, including Docker Compose and GitHub Actions workflows./JSONWhat is json?A text format for exchanging data between systems. It uses key-value pairs and arrays, and every programming language can read and write it. specification

If you prefer not to use JSDoc annotations, write the OpenAPIWhat is openapi?A standard format for describing REST APIs - their endpoints, parameters, and response shapes. Tools can generate documentation and client libraries from it automatically. spec manually:

yaml
# openapi.yaml
openapi: 3.0.0
info:
  title: My API
  version: 1.0.0
  description: API documentation

paths:
  /users:
    get:
      summary: Get all users
      responses:
        '200':
          description: List of users
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'

components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string

Then serve it directly:

import YAML from 'yamljs';
const swaggerDocument = YAML.load('./openapi.yaml');
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));

Postman export

If you already document in Postman:

  1. Create your APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses. collection in Postman
  2. Export as OpenAPI 3.0 format
  3. Import the YAML/JSON into your project

07

Best practices for APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses. documentation

1. Document as you code

Don't leave documentation for "later", later never comes. Add the JSDoc comment when you create the endpointWhat is endpoint?A specific URL path on a server that handles a particular type of request, like GET /api/users..

2. Use tags to organize

Tags group related endpoints in the Swagger UI sidebar:

/**
 * @swagger
 * tags: [Users]
 */

3. Include examples

Examples make documentation concrete and testable:

/**
 * @swagger
 * content:
 *   application/json:
 *     example:
 *       name: "John Doe"
 *       email: "john@example.com"
 */

4. Document errors too

Don't just document the happy path. Show what happens when things go wrong:

/**
 * @swagger
 * responses:
 *   404:
 *     description: User not found
 *     content:
 *       application/json:
 *         schema:
 *           $ref: '#/components/schemas/Error'
 */

5. Keep it up to date

Outdated documentation is worse than none at all, it misleads developers. When you change an endpoint, update the JSDoc immediately. Consider adding documentation checks to your CI pipelineWhat is pipeline?A sequence of automated steps (install, lint, test, build, deploy) that code passes through before reaching production..

08

Quick reference: OpenAPIWhat is openapi?A standard format for describing REST APIs - their endpoints, parameters, and response shapes. Tools can generate documentation and client libraries from it automatically. structure

ElementPurposeExample
pathsDefine endpoints/users, /users/{id}
parametersURL/query paramspage, limit, id
requestBodyPOST/PUT bodyUser creation JSON
responsesPossible responses200, 201, 404, 500
components/schemasReusable structuresUser, Error
securitySchemesAuthenticationBearer token, API key

Good documentation is a product feature, not an afterthought. Invest time in it, and you'll spend less time answering "how do I...?" questions and more time building features.