← All articles
TESTING API Design Tools: OpenAPI, Swagger, and API-First De... 2026-02-09 · 4 min read · api · openapi · swagger

API Design Tools: OpenAPI, Swagger, and API-First Development

Testing 2026-02-09 · 4 min read api openapi swagger rest documentation

API Design Tools: OpenAPI, Swagger, and API-First Development

Most APIs are designed by accident. Someone writes a handler, returns some JSON, and the "API" is whatever the code happens to produce. API-first development flips this: you design the API contract first, then implement it. The tooling around OpenAPI makes this practical, not just aspirational.

OpenAPI Specification

OpenAPI (formerly Swagger) is the industry standard for describing REST APIs. It's a YAML or JSON document that defines your endpoints, request/response schemas, authentication, and more.

# openapi.yaml
openapi: 3.1.0
info:
  title: User API
  version: 1.0.0
  description: User management endpoints

servers:
  - url: https://api.example.com/v1

paths:
  /users:
    get:
      summary: List users
      operationId: listUsers
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
        - name: cursor
          in: query
          schema:
            type: string
      responses:
        '200':
          description: A list of users
          content:
            application/json:
              schema:
                type: object
                properties:
                  users:
                    type: array
                    items:
                      $ref: '#/components/schemas/User'
                  nextCursor:
                    type: string
                    nullable: true

    post:
      summary: Create a user
      operationId: createUser
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUserRequest'
      responses:
        '201':
          description: User created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

components:
  schemas:
    User:
      type: object
      required: [id, name, email, createdAt]
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        email:
          type: string
          format: email
        createdAt:
          type: string
          format: date-time

    CreateUserRequest:
      type: object
      required: [name, email]
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
        email:
          type: string
          format: email

    Error:
      type: object
      required: [code, message]
      properties:
        code:
          type: string
        message:
          type: string

  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

security:
  - bearerAuth: []

API Documentation Renderers

Swagger UI

Swagger UI renders an OpenAPI spec as an interactive documentation page where developers can try API calls directly.

# Docker
docker run -p 8080:8080 \
  -e SWAGGER_JSON=/spec/openapi.yaml \
  -v $(pwd):/spec \
  swaggerapi/swagger-ui

# Or embed in your Express app
npm install swagger-ui-express
import swaggerUi from 'swagger-ui-express';
import spec from './openapi.json';

app.use('/docs', swaggerUi.serve, swaggerUi.setup(spec));

Strength: Interactive "Try it out" button lets developers test endpoints without leaving the docs.

Weakness: The default theme looks dated. Limited customization without forking.

Redocly

Redocly produces beautiful, three-panel API documentation (navigation, content, code samples).

npm install -g @redocly/cli

# Preview docs locally
redocly preview-docs openapi.yaml

# Build static HTML
redocly build-docs openapi.yaml -o docs/index.html

# Lint your OpenAPI spec
redocly lint openapi.yaml

Redocly's linting is the hidden gem — it catches common API design mistakes: missing descriptions, inconsistent naming, unused schemas, and security issues.

# redocly.yaml
extends:
  - recommended
rules:
  operation-description: warn
  tag-description: warn
  no-unused-components: error
  operation-operationId: error

Scalar

Scalar is a modern, open-source API documentation renderer with a clean design and built-in API client.

npx @scalar/cli serve openapi.yaml

It generates documentation that looks modern out of the box — dark mode, collapsible sections, language-specific code examples, and an embedded API testing client. It's quickly becoming the default choice for new projects.

Code Generation

One of the biggest benefits of writing an OpenAPI spec is generating code from it.

Client Generation

# Generate TypeScript client
npx openapi-typescript-codegen \
  --input openapi.yaml \
  --output src/api-client \
  --client fetch

# Or use openapi-typescript for just types
npx openapi-typescript openapi.yaml -o src/api-types.ts

openapi-typescript generates TypeScript types from your spec without any runtime dependencies. This is often the sweet spot — you get type safety without a generated client that feels foreign.

import type { paths } from './api-types';

type ListUsersResponse = paths['/users']['get']['responses']['200']['content']['application/json'];
// { users: User[]; nextCursor: string | null; }

Server Stub Generation

Less commonly, you can generate server stubs from the spec. This ensures your implementation matches the contract. Tools like openapi-generator support this, but in practice most teams find it easier to write the server code and validate against the spec.

API-First Workflow

  1. Design: Write the OpenAPI spec before any code. Use Redocly or Stoplight to edit visually.
  2. Review: PR the spec change. Reviewers discuss the API design, not implementation details.
  3. Mock: Use Prism or Stoplight to run a mock server from the spec. Frontend development starts immediately.
  4. Implement: Build the actual API. The spec is the contract.
  5. Validate: In tests or middleware, validate requests and responses against the spec.
  6. Document: The spec is the documentation — render it with Scalar or Redocly.

Mock Servers

# Prism (from Stoplight)
npm install -g @stoplight/prism-cli
prism mock openapi.yaml
# Now http://localhost:4010/users returns example data

Prism reads your OpenAPI spec and returns realistic example responses. Frontend developers can build against the mock while backend developers implement the real API.

Validation

zod-openapi

If you use Zod for runtime validation (increasingly common in TypeScript), zod-openapi generates OpenAPI schemas from your Zod schemas:

import { z } from 'zod';
import { extendZodWithOpenApi } from 'zod-openapi';

extendZodWithOpenApi(z);

const UserSchema = z.object({
  id: z.string().uuid().openapi({ description: 'Unique user ID' }),
  name: z.string().min(1).max(100),
  email: z.string().email(),
  createdAt: z.string().datetime(),
}).openapi('User');

This is "spec-from-code" rather than "code-from-spec," which some teams prefer because the validation logic and API docs are always in sync.

Recommendations

For new APIs: Start with the OpenAPI spec. Use Redocly CLI for linting. Render docs with Scalar. Generate TypeScript types with openapi-typescript.

For existing APIs without docs: Add openapi-typescript codegen to get types, then gradually build out the spec. Redocly's lint-as-you-go approach catches issues incrementally.

For internal APIs: The spec is valuable even if you never publish docs externally. Type-safe clients generated from the spec eliminate an entire category of integration bugs.