OpenAPI Documentation

Document a Koa API with an OpenAPI Spec and Swagger UI

OpenAPI Documentation

Write an OpenAPI 3.1 specification for a Koa REST API and serve an interactive Swagger UI from the same application using koa-swagger-ui.

5 min read Level 3/5 #koa#openapi#swagger
What you'll learn
  • Structure an OpenAPI 3.1 document describing your Koa API's paths and schemas
  • Serve the raw spec as JSON from a dedicated Koa route
  • Mount Swagger UI so developers can explore and test the API in a browser

An OpenAPI specification is a machine-readable contract that describes every endpoint, parameter, request body, and response schema in your API. Tools can generate client SDKs, mock servers, and interactive documentation from it.

Install Dependencies

npm install koa-swagger-ui

No code-generation library is required — you can write the spec as a plain JS object and let Koa serve it.

Write the OpenAPI Document

Create src/openapi.js and export the spec:

// src/openapi.js
export const spec = {
  openapi: "3.1.0",
  info: {
    title: "Articles API",
    version: "1.0.0",
    description: "A simple Koa REST API for managing articles.",
  },
  paths: {
    "/articles": {
      get: {
        summary: "List all articles",
        parameters: [
          { name: "limit",  in: "query", schema: { type: "integer", default: 20 } },
          { name: "offset", in: "query", schema: { type: "integer", default: 0  } },
        ],
        responses: {
          "200": {
            description: "Paginated list of articles",
            content: {
              "application/json": {
                schema: { $ref: "#/components/schemas/ArticleList" },
              },
            },
          },
        },
      },
      post: {
        summary: "Create an article",
        requestBody: {
          required: true,
          content: {
            "application/json": {
              schema: { $ref: "#/components/schemas/CreateArticle" },
            },
          },
        },
        responses: {
          "201": { description: "Created" },
          "422": { description: "Validation failed" },
        },
      },
    },
  },
  components: {
    schemas: {
      Article: {
        type: "object",
        properties: {
          id:    { type: "integer" },
          title: { type: "string"  },
          body:  { type: "string"  },
        },
      },
      ArticleList: {
        type: "object",
        properties: {
          data:   { type: "array", items: { $ref: "#/components/schemas/Article" } },
          total:  { type: "integer" },
          limit:  { type: "integer" },
          offset: { type: "integer" },
        },
      },
      CreateArticle: {
        type: "object",
        required: ["title", "body"],
        properties: {
          title: { type: "string", minLength: 1, maxLength: 200 },
          body:  { type: "string", minLength: 1 },
        },
      },
    },
  },
};

Serve the Spec as JSON

Add a route that returns the spec so tools can fetch it at a stable URL:

import Router from "@koa/router";
import { spec } from "./openapi.js";

const docsRouter = new Router();

docsRouter.get("/openapi.json", async (ctx) => {
  ctx.type = "application/json";
  ctx.body = spec;
});

Mount Swagger UI

koa-swagger-ui serves the HTML explorer and points it at your spec URL:

import { koaSwagger } from "koa-swagger-ui";

app.use(
  koaSwagger({
    routePrefix: "/docs",           // browse to http://localhost:3000/docs
    swaggerOptions: {
      url: "/openapi.json",         // spec URL served above
    },
  })
);

Mount the docs router and Swagger UI before your API routers:

app.use(docsRouter.routes());
app.use(docsRouter.allowedMethods());
app.use(articlesRouter.routes());
app.use(articlesRouter.allowedMethods());

Keeping the Spec in Sync

For larger APIs, consider generating the spec from your Zod schemas using zod-to-openapi — the schema is the single source of truth, and the OpenAPI document is derived from it automatically.

ToolApproachBest for
Hand-written YAML/JSSpec-firstSmall, stable APIs
zod-to-openapiCode-first via ZodTeams already using Zod validation
koa-swagger-decoratorDecorator annotationsTypeScript / class-based controllers

Up Next

With a fully documented REST API in place, the next section introduces authentication — protecting these endpoints with JWTs and session cookies.

Authentication Overview →