100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Node.js & Express Backend
30 minintermediate

OpenAPI 3.0 / Swagger Documentation

OpenAPI 3.0 / Swagger Documentation

An API without documentation is an API that only its author can use. OpenAPI 3.0 is the industry-standard specification for describing REST APIs: it defines your endpoints, request parameters, request bodies, response shapes, authentication schemes, and error formats in a machine-readable YAML or JSON format. From an OpenAPI spec, tools can generate interactive documentation, client SDKs in any language, mock servers, and automated tests. In Node.js, swagger-jsdoc generates the spec from JSDoc comments in your source code, and swagger-ui-express serves the interactive Swagger UI.

Analogy🏏Cricket
Think of it like cricket: The ICC's playing conditions document is the OpenAPI spec of cricket. It precisely defines every rule — the dimensions of the pitch (endpoint schema), the valid methods of dismissal (HTTP methods), the fielding restrictions in powerplay (security requirements), and the signals umpires must use (response codes). Without it, every national board would interpret the game differently and no international match would be possible. Your OpenAPI spec is the playing conditions that let external developers integrate with your API without needing to call you every day. Rohit Sharma knows exactly what to expect at every Test venue because the ICC spec is authoritative and public.

Defining the OpenAPI Spec with swagger-jsdoc

swagger-jsdoc reads JSDoc comments annotated with @openapi (or @swagger) tags from your route files and assembles them into a complete OpenAPI 3.0 document. The base spec (info, servers, components/schemas, securitySchemes) is defined once in a central config. Route-level docs are co-located with the route code, keeping documentation and implementation together.

Analogy🏏Cricket
🏏 Think of it like cricket: swagger-jsdoc assembles your official match programme by reading notes written right next to the action. Each route file carries JSDoc comments tagged @openapi — like a scorer's annotations pencilled in the margin beside each over — and the tool gathers them into one complete OpenAPI 3.0 document, the printed programme. The base spec (info, servers, shared schemas, security schemes) is defined once centrally, the way the tournament's fixed details — venue, teams, rules — are set on the programme's front page and never repeated. The route-level docs stay co-located with the route code, exactly as the ball-by-ball notes live right in the scorebook beside the play they describe, so documentation and implementation move together and never drift apart. The payoff: writing docs beside the code and assembling them automatically means your API programme is always generated from the live source, so it can't fall out of date the way a separately-maintained booklet would.
bash
npm install swagger-jsdoc swagger-ui-express
javascript
// config/swagger.js
const swaggerJsdoc = require('swagger-jsdoc');

const options = {
  definition: {
    openapi: '3.0.0',
    info: {
      title:       'Cricket API',
      version:     '1.0.0',
      description: 'Node.js & Express Backend — SkillVeris Course 4 Example API',
      contact:     { name: 'API Support', email: '[email protected]' }
    },
    servers: [
      { url: 'http://localhost:3000', description: 'Development' },
      { url: 'https://api.myapp.com',  description: 'Production' }
    ],
    components: {
      securitySchemes: {
        bearerAuth: {
          type: 'http', scheme: 'bearer', bearerFormat: 'JWT'
        }
      },
      schemas: {
        Product: {
          type: 'object',
          required: ['name', 'price'],
          properties: {
            id:    { type: 'string', example: '64abc123' },
            name:  { type: 'string', example: 'Cricket Bat' },
            price: { type: 'number', example: 120.00 },
            category: { type: 'string', example: 'equipment' }
          }
        },
        Error: {
          type: 'object',
          properties: {
            error: { type: 'string', example: 'Not found' }
          }
        }
      }
    }
  },
  apis: ['./routes/**/*.js']  // paths to files with @openapi annotations
};

module.exports = swaggerJsdoc(options);

Annotating Routes with JSDoc

Each route gets a JSDoc block with @openapi tags describing its method, path, parameters, request body, and all possible responses. The descriptions appear verbatim in the Swagger UI, so write them for your API consumers, not for yourself.

Analogy🏏Cricket
🏏 Think of it like cricket: annotating each route with a JSDoc @openapi block is like writing a clear, complete entry in the official scorecard for every delivery — this route's method and path are the bowler and over, its parameters and request body are the field settings and the ball bowled, and its possible responses are every outcome that could follow: run, wicket, wide, no-ball. Crucially, these descriptions appear verbatim in the Swagger UI, printed word for word on the programme spectators actually read — so you write them for your API consumers, the crowd in the stands, not as private shorthand only you understand, just as a public scorecard must make sense to every spectator, not only the team scorer. The payoff: a thorough, consumer-facing JSDoc block on every route means the generated documentation reads as a genuine guide for the developers using your API, complete down to every response your route can return.
javascript
// routes/products.js

/**
 * @openapi
 * /api/v1/products:
 *   get:
 *     summary: List all products
 *     tags: [Products]
 *     parameters:
 *       - in: query
 *         name: page
 *         schema: { type: integer, default: 1 }
 *         description: Page number
 *       - in: query
 *         name: limit
 *         schema: { type: integer, default: 10, maximum: 100 }
 *         description: Items per page
 *       - in: query
 *         name: category
 *         schema: { type: string }
 *         description: Filter by category
 *     responses:
 *       200:
 *         description: Paginated product list
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 data:
 *                   type: array
 *                   items:
 *                     $ref: '#/components/schemas/Product'
 *                 meta:
 *                   type: object
 *                   properties:
 *                     total: { type: integer }
 *                     page:  { type: integer }
 *                     pages: { type: integer }
 */
router.get('/', asyncHandler(getProducts));

/**
 * @openapi
 * /api/v1/products:
 *   post:
 *     summary: Create a new product
 *     tags: [Products]
 *     security:
 *       - bearerAuth: []
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             $ref: '#/components/schemas/Product'
 *     responses:
 *       201:
 *         description: Product created
 *         content:
 *           application/json:
 *             schema:
 *               $ref: '#/components/schemas/Product'
 *       401:
 *         description: Unauthenticated
 *       403:
 *         description: Forbidden
 *       422:
 *         description: Validation error
 */
router.post('/', authenticate, authorize('write:products'), asyncHandler(createProduct));
Lesson 33 of 36
0% complete