Documenting APIs with OpenAPI and Swagger UI

Intermediate
13 min

Documenting APIs with OpenAPI and Swagger UI

OpenAPI is the industry-standard, machine-readable way to describe a REST API: every path, parameter, body, response and security scheme in one YAML or JSON document that can render documentation, validate requests and generate client SDKs. In this lesson you will learn the structure of an OpenAPI document, how to serve it with Swagger UI in Express, and how to keep it truthful.

OpenAPI and Swagger

Swagger was the original name of the specification and remains the name of the tooling (Swagger UI, Swagger Editor); the specification itself became OpenAPI in 2016. The current version, 3.1, uses plain JSON Schema for its schemas, so everything you know about JSON Schema validation applies directly.

Anatomy of an OpenAPI Document

yaml
openapi: 3.1.0 info: title: Bookstore API version: 1.2.0 paths: /books: get: summary: List books operationId: listBooks parameters: - name: genre in: query schema: { type: string } - name: limit in: query schema: { type: integer, minimum: 1, maximum: 100, default: 20 } responses: "200": description: A page of books content: application/json: schema: type: array items: { $ref: "#/components/schemas/Book" } post: summary: Create a book operationId: createBook security: [{ bearerAuth: [] }] requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/NewBook" } responses: "201": description: Created "422": description: Validation failed components: securitySchemes: bearerAuth: { type: http, scheme: bearer, bearerFormat: JWT } schemas: NewBook: type: object required: [title, author] properties: title: { type: string, maxLength: 200 } author: { type: string } Book: allOf: - $ref: "#/components/schemas/NewBook" - type: object required: [id] properties: id: { type: string, examples: ["bk_42"] }

paths map URL templates to operations keyed by HTTP method; each operation lists parameters (in: query, path or header), an optional requestBody, and responses keyed by status code. components holds reusable schemas and security schemes referenced with $ref, and operationId gives each operation a stable name that code generators use.

Serving Swagger UI from Express

swagger-ui-express renders the document as an interactive page where readers can try requests live:

javascript
const fs = require("fs"); const YAML = require("yaml"); const swaggerUi = require("swagger-ui-express"); const spec = YAML.parse(fs.readFileSync("./openapi.yaml", "utf8")); app.use("/docs", swaggerUi.serve, swaggerUi.setup(spec)); app.get("/openapi.json", (req, res) => res.json(spec));

Publishing the raw document at /openapi.json matters as much as the page: it is what Postman imports, SDK generators read and gateways validate against.

Design-First or Code-First

| Approach | How | Strengths | |---|---|---| | Design-first | Write openapi.yaml before code and review it like a pull request | Contract agreed early; frontend and backend work in parallel | | Code-first | Annotate routes (swagger-jsdoc comments, decorators in NestJS or FastAPI) and generate the document | Never drifts from the implementation |

Either way, make the document authoritative by validating traffic against it. express-openapi-validator rejects violating requests with a 400, so an undocumented parameter simply does not work:

javascript
const OpenApiValidator = require("express-openapi-validator"); app.use(OpenApiValidator.middleware({ apiSpec: "./openapi.yaml", validateRequests: true }));

Tips

  • Document error responses (401, 404, 422, 429) with the Problem Details schema.
  • Lint the document in CI with Spectral, and generate typed clients (openapi-typescript) so breaking changes surface as compile errors.
Quick Quiz
Question 1 of 2

In an OpenAPI document, where do reusable schemas such as `Book` live?

Key Takeaways

  • OpenAPI (formerly Swagger) describes paths, parameters, bodies, responses and security in one file.
  • Reusable pieces live in components and are referenced with $ref; operationId names each operation.
  • swagger-ui-express serves interactive docs; also publish the raw document at /openapi.json.
  • Choose design-first for early review or code-first to avoid drift; enforce the contract either way.
  • Document errors, lint in CI, and generate clients from the same file.

Next lesson: Automated API Testing with Jest and Supertest — turn the contract into a test suite that runs on every commit.

Documenting APIs with OpenAPI and Swagger UI - REST APIs | CodeYourCraft | CodeYourCraft