Desishub Lessons
Node Js and Typescript
Implementing API Documentation using Swagger

A Beginner's Guide to Implementing API Documentation with Swagger (with Prisma Integration)

In today's world of web development, creating clear and comprehensive API documentation is crucial. One of the most popular tools for this purpose is Swagger (now part of the OpenAPI Initiative). This guide will walk you through the process of implementing API documentation using Swagger in a Node.js and Express environment.

What is Swagger?

Swagger is a set of open-source tools that helps developers design, build, document, and consume RESTful web services. It allows you to describe your API structure in a way that machines can read and understand.

Prerequisites

Before we begin, make sure you have the following installed:

  • Node.js
  • npm (Node Package Manager)
  • An existing Express.js project (we'll assume you're using TypeScript)

Step 1: Installation

First, let's install the necessary packages. Open your terminal and run:

npm install swagger-jsdoc swagger-ui-express
npm install --save-dev @types/swagger-jsdoc @types/swagger-ui-express

These packages will allow us to generate Swagger documentation and serve it through a UI.

Step 2: Set Up Swagger Configuration

Create a new file named swagger.ts in your project root and add the following code:

import swaggerJsdoc from "swagger-jsdoc";
 
const options = {
  definition: {
    openapi: "3.0.0",
    info: {
      title: "My API",
      version: "1.0.0",
      description: "A sample API for learning Swagger",
    },
    servers: [
      {
        url: "http://localhost:3000",
        description: "Development server",
      },
    ],
  },
  apis: ["./src/routes/*.ts"], // Path to the API docs
};
 
export const specs = swaggerJsdoc(options);

This configuration file sets up the basic information about your API and tells Swagger where to look for your API documentation.

Step 3: Integrate Swagger with Express

Now, let's integrate Swagger into your Express application. In your main application file (e.g., app.ts), add the following:

import express from "express";
import swaggerUi from "swagger-ui-express";
import { specs } from "./swagger";
 
const app = express();
 
// Swagger UI
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(specs));
 
// Your routes and other middleware here...
 
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

This sets up a route /api-docs which will serve your Swagger documentation.

Step 4: Document Your Routes

Now comes the fun part – documenting your actual API endpoints. You'll do this using JSDoc-style comments above your route handlers. Here's an example:

import express from "express";
const router = express.Router();
 
/**
 * @swagger
 * /api/users:
 *   get:
 *     summary: Retrieve a list of users
 *     description: Retrieve a list of users from the database.
 *     responses:
 *       200:
 *         description: A list of users.
 *         content:
 *           application/json:
 *             schema:
 *               type: array
 *               items:
 *                 type: object
 *                 properties:
 *                   id:
 *                     type: integer
 *                     description: The user ID.
 *                   name:
 *                     type: string
 *                     description: The user's name.
 */
router.get("/users", (req, res) => {
  // Your route logic here
});
 
export default router;

Adding Home Page and More routes

Okay lets Modify our index.ts file

import express from "express";
import {
  createUser,
  getUsers,
  getUserById,
} from "../controllers/userController";
 
const router = express.Router();
 
/**
 * @swagger
 * /api/users:
 *   post:
 *     summary: Create a new user
 *     description: Creates a new user in the system.
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             properties:
 *               name:
 *                 type: string
 *               email:
 *                 type: string
 *     responses:
 *       201:
 *         description: Created
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 id:
 *                   type: integer
 *                 name:
 *                   type: string
 *                 email:
 *                   type: string
 */
router.post("/users", createUser);
 
/**
 * @swagger
 * /api/users:
 *   get:
 *     summary: Retrieve a list of users
 *     description: Retrieve a list of users from the database.
 *     responses:
 *       200:
 *         description: A list of users.
 *         content:
 *           application/json:
 *             schema:
 *               type: array
 *               items:
 *                 type: object
 *                 properties:
 *                   id:
 *                     type: integer
 *                   name:
 *                     type: string
 *                   email:
 *                     type: string
 */
router.get("/users", getUsers);
 
/**
 * @swagger
 * /api/users/{id}:
 *   get:
 *     summary: Get a user by ID
 *     description: Retrieve a single user by their ID.
 *     parameters:
 *       - in: path
 *         name: id
 *         required: true
 *         schema:
 *           type: integer
 *     responses:
 *       200:
 *         description: A single user.
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 id:
 *                   type: integer
 *                 name:
 *                   type: string
 *                 email:
 *                   type: string
 *       404:
 *         description: User not found.
 */
router.get("/users/:id", getUserById);
 
export default router;

Step 5: Create a Home page for the API

To create a home page for your API when a user visits the root URL ("/"), you can add a simple route in your main application file. Here's how you can do it:

  1. First, create a simple HTML file for your home page. You can name it home.html and place it in a public folder in your project root:

see API html with tailwind here https://play.tailwindcss.com/nn6kvKMomm (opens in a new tab)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My API</title>
    <style>
      body {
        font-family: Arial, sans-serif;
        line-height: 1.6;
        padding: 20px;
      }
      h1 {
        color: #333;
      }
      a {
        color: #007bff;
        text-decoration: none;
      }
      a:hover {
        text-decoration: underline;
      }
    </style>
  </head>
  <body>
    <h1>Welcome to My API</h1>
    <p>
      This is the home page for my API. To view the API documentation, please
      visit the <a href="/api-docs">Swagger UI</a>.
    </p>
  </body>
</html>
  1. Then, in your main application file (e.g., app.ts), add the following:
import express from "express";
import path from "path";
import swaggerUi from "swagger-ui-express";
import { specs } from "./swagger";
 
const app = express();
 
// Serve static files from the 'public' directory
app.use(express.static(path.join(__dirname, "public")));
 
// Home route
app.get("/", (req, res) => {
  res.sendFile(path.join(__dirname, "public", "home.html"));
});
 
// Swagger UI
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(specs));
 
// Your API routes
app.use("/api", userRouter);
 
// ... rest of your server setup

Using Prisma Schema in Swagger Documentation

If you're using Prisma, you already have a well-defined schema for your database models. We can leverage this schema to generate TypeScript types and use them in our Swagger documentation. Here's how to do it:

  1. First, make sure you have your Prisma schema defined in prisma/schema.prisma. For example:
// prisma/schema.prisma
 
model User {
  id    Int     @id @default(autoincrement())
  name  String
  email String  @unique
  age   Int?
}
  1. Generate Prisma client and TypeScript types:
npx prisma generate

This command generates TypeScript types based on your Prisma schema.

  1. Install @prisma/client if you haven't already:
npm install @prisma/client
  1. Create a file to export Prisma-generated types. Let's call it src/models/prismaTypes.ts:
// src/models/prismaTypes.ts
 
import { Prisma } from "@prisma/client";
 
export type User = Prisma.UserGetPayload<{}>;
export type CreateUserInput = Prisma.UserCreateInput;
  1. Now, we'll need to install a package that helps convert TypeScript to JSON Schema:
npm install typescript-json-schema
  1. Add a script to your package.json to generate JSON schemas:
"scripts": {
  "generate-schemas": "typescript-json-schema ./src/models/prismaTypes.ts '*' --out ./src/schemas.json"
}
  1. Run this script to generate the JSON schemas:
npm run generate-schemas
  1. Update your Swagger configuration in swagger.ts:
import swaggerJsdoc from "swagger-jsdoc";
import schemas from "./schemas.json";
 
const options = {
  definition: {
    openapi: "3.0.0",
    info: {
      title: "My API",
      version: "1.0.0",
      description: "A sample API using Prisma and Swagger",
    },
    servers: [
      {
        url: "http://localhost:3000",
        description: "Development server",
      },
    ],
    components: {
      schemas: schemas,
    },
  },
  apis: ["./src/routes/*.ts"],
};
 
export const specs = swaggerJsdoc(options);
  1. Update your route documentation to use these schemas:
// src/routes/userRoutes.ts
 
import express from "express";
import {
  createUser,
  getUsers,
  getUserById,
} from "../controllers/userController";
 
const router = express.Router();
 
/**
 * @swagger
 * /api/users:
 *   post:
 *     summary: Create a new user
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             $ref: '#/components/schemas/CreateUserInput'
 *     responses:
 *       201:
 *         description: Created
 *         content:
 *           application/json:
 *             schema:
 *               $ref: '#/components/schemas/User'
 */
router.post("/users", createUser);
 
/**
 * @swagger
 * /api/users:
 *   get:
 *     summary: Retrieve a list of users
 *     responses:
 *       200:
 *         description: A list of users.
 *         content:
 *           application/json:
 *             schema:
 *               type: array
 *               items:
 *                 $ref: '#/components/schemas/User'
 */
router.get("/users", getUsers);
 
/**
 * @swagger
 * /api/users/{id}:
 *   get:
 *     summary: Get a user by ID
 *     parameters:
 *       - in: path
 *         name: id
 *         required: true
 *         schema:
 *           type: integer
 *     responses:
 *       200:
 *         description: A single user.
 *         content:
 *           application/json:
 *             schema:
 *               $ref: '#/components/schemas/User'
 *       404:
 *         description: User not found.
 */
router.get("/users/:id", getUserById);
 
export default router;

By following these steps, you're now using your Prisma schema to generate TypeScript types, which are then used to create JSON schemas for your Swagger documentation. This approach has several benefits:

  1. Your API documentation will always be in sync with your database schema.
  2. You can make changes to your Prisma schema and have them reflected in both your code and your documentation.
  3. It provides a single source of truth for your data models.
  4. You get the benefits of Prisma's powerful ORM along with comprehensive API documentation.

Remember to run the generate-schemas script whenever you make changes to your Prisma schema to keep your documentation up to date.

This setup will serve the home.html file when a user visits the root URL of your API.

Step 6: Test Your Documentation and Home Page

Start your Express server and navigate to http://localhost:3000 in your web browser. You should see your API home page. From there, you can click the link to view the Swagger UI at http://localhost:3000/api-docs, where you'll see your documented endpoints.

Project Structure

Online Mermaid Live Editor: The easiest way is to use the Mermaid Live Editor:

Go to https://mermaid.live/ (opens in a new tab) Paste the Mermaid code into the left panel The diagram will render in the right panel Click on the "Download SVG" button at the top right In the dropdown, select "PNG" instead of SVG The PNG will be downloaded to your device

graph TD
    A[Project Root] --> B[src/]
    A --> C[public/]
    A --> D[package.json]
    A --> E[tsconfig.json]
    A --> F[swagger.ts]
    A --> P[prisma/]
 
    B --> G[app.ts]
    B --> H[routes/]
    B --> I[controllers/]
    B --> M[models/]
    B --> N[schemas.json]
 
    H --> J[userRoutes.ts]
 
    I --> K[userController.ts]
 
    M --> Q[prismaTypes.ts]
 
    P --> R[schema.prisma]
 
    C --> L[home.html]
 
    style A fill:#f9f,stroke:#333,stroke-width:2px
    style B fill:#bbf,stroke:#333,stroke-width:2px
    style C fill:#bfb,stroke:#333,stroke-width:2px
    style H fill:#fbb,stroke:#333,stroke-width:2px
    style I fill:#fbf,stroke:#333,stroke-width:2px
    style M fill:#bff,stroke:#333,stroke-width:2px
    style P fill:#ffb,stroke:#333,stroke-width:2px

(opens in a new tab)