OpenAPI 3.0 Complete Guide — Design RESTful APIs Right

Complete OpenAPI 3.0 specification guide: design RESTful APIs with schemas, parameters, security, responses, and generate SDKs automatically. Includes Swagger UI setup.

What is OpenAPI?

OpenAPI (formerly Swagger) is a language-agnostic specification for describing REST APIs. A single YAML or JSON file describes your entire API: endpoints, request/response schemas, authentication, and error codes. From this specification you can generate interactive documentation (Swagger UI), client SDKs in 40+ languages, server stubs, and test suites.

OpenAPI 3.0 is the current major version (3.1 is the latest, adding full JSON Schema compatibility). The ecosystem is mature and supported by every major API framework.

Minimal OpenAPI 3.0 Document

openapi: 3.0.3
info:
  title: User API
  version: 1.0.0
  description: Manage users in the system
  contact:
    name: API Support
    email: [email protected]

servers:
  - url: https://api.example.com/v1
    description: Production
  - url: http://localhost:8000/v1
    description: Local development

paths:
  /users:
    get:
      summary: List all users
      operationId: listUsers
      tags: [Users]
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'

Schema Components

Define reusable schemas under components/schemas and reference them with $ref:

components:
  schemas:
    User:
      type: object
      required: [id, name, email]
      properties:
        id:
          type: integer
          format: int64
          example: 42
          readOnly: true
        name:
          type: string
          minLength: 1
          maxLength: 100
          example: "Alice Smith"
        email:
          type: string
          format: email
          example: "[email protected]"
        role:
          type: string
          enum: [admin, user, viewer]
          default: user
        createdAt:
          type: string
          format: date-time
          readOnly: true

    CreateUserRequest:
      type: object
      required: [name, email]
      properties:
        name:
          type: string
        email:
          type: string
          format: email
        role:
          type: string
          enum: [admin, user, viewer]

Path Parameters and Request Bodies

paths:
  /users/{userId}:
    parameters:
      - name: userId
        in: path
        required: true
        schema:
          type: integer
          format: int64

    get:
      summary: Get a user by ID
      operationId: getUser
      tags: [Users]
      responses:
        '200':
          description: User found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '404':
          $ref: '#/components/responses/NotFound'

    put:
      summary: Update a user
      operationId: updateUser
      tags: [Users]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUserRequest'
            example:
              name: "Alice Updated"
              email: "[email protected]"
      responses:
        '200':
          description: Updated user
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'

Security Schemes

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key

    OAuth2:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: https://auth.example.com/oauth/authorize
          tokenUrl: https://auth.example.com/oauth/token
          scopes:
            read: Read access
            write: Write access

# Apply globally
security:
  - BearerAuth: []

# Or per-operation (overrides global)
paths:
  /public/health:
    get:
      security: []   # No auth required

Reusable Responses and Error Schemas

components:
  responses:
    BadRequest:
      description: Invalid request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'

    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'

    Unauthorized:
      description: Authentication required
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'

  schemas:
    Error:
      type: object
      required: [code, message]
      properties:
        code:
          type: string
          example: "VALIDATION_ERROR"
        message:
          type: string
          example: "Email is invalid"
        details:
          type: array
          items:
            type: object

API-First Development Workflow

Write the OpenAPI spec first, before writing any code:

  1. Design the spec collaboratively (frontend + backend + product)
  2. Generate mock servers with Prism or Stoplight — frontend can start building immediately
  3. Generate server stubs for your language (FastAPI, Express, Spring)
  4. Implement business logic in the generated stubs
  5. Generate client SDKs for consumers
  6. Run contract tests against the spec continuously
# Generate mock server
npx @stoplight/prism-cli mock openapi.yaml

# Generate Python client
npx @openapitools/openapi-generator-cli generate \
  -i openapi.yaml \
  -g python \
  -o ./client-sdk

# Generate FastAPI server stub
npx @openapitools/openapi-generator-cli generate \
  -i openapi.yaml \
  -g python-fastapi \
  -o ./server

Swagger UI Setup

# FastAPI — automatic OpenAPI + Swagger UI
from fastapi import FastAPI

app = FastAPI(
    title="User API",
    version="1.0.0",
    docs_url="/docs",      # Swagger UI
    redoc_url="/redoc",    # ReDoc alternative
)

# Express.js with swagger-ui-express
const swaggerUi = require('swagger-ui-express');
const spec = require('./openapi.json');

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

Frequently Asked Questions

OpenAPI 3.0 vs 3.1 — which should I use?

OpenAPI 3.1 adds full JSON Schema compatibility and is the recommended choice for new projects. However, tooling support for 3.1 is still catching up. If you rely heavily on code generation tools, check their 3.1 support status first.

Should I write the spec by hand or generate it from code?

For new projects: write the spec first (API-first design). For existing projects: generate from code annotations (FastAPI, Springdoc, NestJS Swagger) and then export to a spec file. Use DevKits OpenAPI Generator Pro to scaffold complete OpenAPI specs from your requirements.

How do I validate request bodies against my OpenAPI schema?

Most frameworks do this automatically (FastAPI, Hapi, express-openapi-validator). For manual validation, use ajv in Node.js or jsonschema in Python. Test your JSON payloads with the DevKits JSON Formatter.