Menu

Topic 8 of 8

API Documentation OpenAPI Basics

Learn API Documentation OpenAPI Basics for free with explanations, exercises, and a quick test (for Backend Engineer).

Published: January 20, 2026 | Updated: January 20, 2026

Who this is for

  • Backend engineers who want to define or maintain HTTP APIs clearly and consistently.
  • Developers moving from ad-hoc API docs to a standard like OpenAPI 3.x.
  • Anyone collaborating across teams (backend, frontend, QA, DevRel) on API contracts.

Prerequisites

  • Basics of HTTP: methods (GET/POST/PUT/PATCH/DELETE), status codes.
  • Comfort with JSON and/or YAML.
  • Familiarity with REST-style endpoints.

Why this matters

In real backend work, clear API documentation saves time and prevents bugs. With OpenAPI you can:

  • Design endpoints before writing code (contract-first) or document existing ones (code-first).
  • Auto-generate SDKs, server stubs, and test clients.
  • Align backend, frontend, QA, and stakeholders with one reliable source of truth.

Concept explained simply

OpenAPI is a standardized way to describe your HTTP API in a single file (YAML or JSON). You list your endpoints, parameters, request bodies, responses, and reusable pieces. Tools can read that file to generate docs, clients, tests, and more.

Mental model

  • Info and servers: who you are and where your API lives.
  • Paths: each endpoint with its operations (get/post/etc).
  • Components: your reusable toolbox (schemas, parameters, responses, security, etc.).
  • Security: how clients authenticate (e.g., bearer tokens).

Core building blocks of an OpenAPI file

Minimal skeleton
openapi: 3.0.3
info:
  title: Sample API
  version: 1.0.0
servers:
  - url: https://api.example.com/v1
paths:
  /health:
    get:
      summary: Health check
      responses:
        '200':
          description: OK
Adding a request body and response schemas
openapi: 3.0.3
info:
  title: Users API
  version: 1.0.0
paths:
  /users:
    post:
      summary: Create user
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email, password]
              properties:
                email:
                  type: string
                  format: email
                password:
                  type: string
                  minLength: 8
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                required: [id, email]
                properties:
                  id:
                    type: integer
                  email:
                    type: string
                    format: email
Reusables with components and security
openapi: 3.0.3
info:
  title: Profiles API
  version: 1.0.0
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
  responses:
    NotFound:
      description: Resource not found
    UnauthorizedError:
      description: Access token is missing or invalid
  schemas:
    Profile:
      type: object
      required: [id, name]
      properties:
        id:
          type: string
        name:
          type: string
paths:
  /profiles/{id}:
    get:
      security:
        - BearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Profile'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFound'

Worked examples

1) Simple GET health endpoint
openapi: 3.0.3
info:
  title: Health API
  version: 1.0.0
paths:
  /health:
    get:
      summary: Health check
      tags: [System]
      responses:
        '200':
          description: Service is healthy

Why it works: No body needed; a 200 with a short description is enough.

2) GET with query params and typed response
openapi: 3.0.3
info:
  title: Todo API
  version: 1.0.0
paths:
  /todos:
    get:
      summary: List todos
      parameters:
        - name: completed
          in: query
          description: Filter by completion status
          required: false
          schema:
            type: boolean
      responses:
        '200':
          description: List of todos
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  required: [id, title, completed]
                  properties:
                    id: { type: integer }
                    title: { type: string }
                    completed: { type: boolean }

Why it works: Query parameter declared at operation level; response schema is an array of objects.

3) POST create with examples and error reuse
openapi: 3.0.3
info:
  title: Orders API
  version: 1.0.0
components:
  responses:
    BadRequest:
      description: Invalid input
  schemas:
    Order:
      type: object
      required: [id, status]
      properties:
        id: { type: integer }
        status: { type: string, enum: [processing, shipped, canceled] }
paths:
  /orders:
    post:
      summary: Create order
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [items]
              properties:
                items:
                  type: array
                  items:
                    type: object
                    required: [sku, qty]
                    properties:
                      sku: { type: string }
                      qty: { type: integer, minimum: 1 }
            examples:
              valid:
                value: { items: [ { sku: 'ABC-1', qty: 2 } ] }
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '400':
          $ref: '#/components/responses/BadRequest'

Why it works: Request example helps consumers; 400 response reuses a component for consistency.

Step-by-step: Write your first spec

  1. State the version and info: add openapi: 3.0.3, title, and version.
  2. List servers: your base URL(s), e.g., production and staging.
  3. Add one path with one operation. Start minimal: summary + a 200 response.
  4. Introduce requestBody or parameters as needed.
  5. Extract repeated shapes into components.schemas.
  6. Extract repeated responses or parameters into components.
  7. Add security schemes and reference them on operations that require auth.
  8. Validate the file with a linter and iterate on feedback from teammates.

Exercises

Work through these directly in your editor. Keep them small and valid. Then compare with the solutions below.

  1. Exercise 1: Describe GET /todos with an optional boolean query parameter completed and a 200 JSON array of todos (each todo has id integer, title string, completed boolean).
  2. Exercise 2: Describe PATCH /orders/{id} with a required path parameter id (integer) and a JSON request body allowing the client to change status to one of processing|shipped|canceled. Return 200 with the updated order and 404 when not found. Reuse a NotFound response from components.

Checklist to self-check

  • Did you put completed under parameters with in: query?
  • Did you use requestBody for JSON payloads (not query/headers)?
  • Are status codes written as strings like '200'?
  • Are required fields explicitly listed under required: arrays?
  • Did you reference components with $ref correctly (absolute path from #/components/...)?

Common mistakes and how to self-check

  • Putting the body in parameters: In OpenAPI 3, use requestBody. If you see in: body, it’s wrong (that was Swagger 2.0).
    Fix: Move payload into requestBody -> content -> application/json.
  • Missing required flags: Required path params must have required: true.
    Self-check: All {param} in paths appear as parameters with in: path and required: true.
  • Un-typed schemas: Forgetting type: leads to ambiguous clients.
    Self-check: Every schema has explicit type and property types.
  • Status codes as numbers: Keys must be strings.
    Self-check: Quotes around status codes like '201'.
  • Duplicated shapes: Copy-paste schemas across operations.
    Fix: Extract to components.schemas and $ref.

Practical projects

  • Project A: Describe a minimal Blog API with posts and comments.
    Include: GET/POST for posts, GET for comments, reusable Post and Comment schemas, pagination query params.
  • Project B: Secure endpoints with bearer auth.
    Include: components.securitySchemes.BearerAuth, mark selected operations with security, and add a shared Unauthorized response.
  • Project C: Error model.
    Include: a reusable Error schema and BadRequest/NotFound responses referencing it.

Learning path

  • Start: OpenAPI file structure, paths, request/response basics.
  • Next: Components and reusability (schemas, parameters, responses, security).
  • Then: Examples, enums, validation keywords (minLength, format, etc.).
  • Finally: API versioning strategy, pagination patterns, and mock testing based on the spec.

Mini challenge

Extend a GET /users endpoint with pagination and errors using components. Requirements:

  • Query parameters: page (integer, min 1), pageSize (integer, 1–100).
  • 200 response returns an object with items (array of User) and total (integer).
  • Use a reusable User schema.
  • Include a reusable BadRequest response for invalid parameters.

Next steps

  • Complete the exercises below and compare to the provided solutions.
  • Take the Quick Test to check your understanding. Note: anyone can take the test; only logged-in users get saved progress.
  • Refactor one of your team’s existing endpoints into a clean, reusable OpenAPI component set.

Practice Exercises

2 exercises to complete

Instructions

Write an OpenAPI 3.x snippet for GET /todos with an optional boolean query parameter completed. The 200 response returns a JSON array of todos, where each todo has id (integer), title (string), and completed (boolean).

Expected Output
An OpenAPI snippet with a GET /todos path, a query parameter named completed (boolean, not required), and a 200 JSON array response with item schema including id, title, completed.

API Documentation OpenAPI Basics — Quick Test

Test your knowledge with 7 questions. Pass with 70% or higher.

7 questions70% to pass

Have questions about API Documentation OpenAPI Basics?

AI Assistant

Ask questions about this tool