Skip to content

OpenAPI

  • OpenAPI (formerly known as Swagger) is a standard, language-agnostic contract for describing REST APIs. The same OpenAPI file works whether the API is written in PHP, Java, or any other language.
  • It lets both humans and computers understand an API’s capabilities: the endpoints it exposes, the data each endpoint expects, and the data it returns.
  • Tools read an OpenAPI file to generate interactive documentation and client or server code.
  • OpenAPI files are written in YAML or JSON. This course uses YAML because it is easier for humans to read and write.

OpenAPI files in this course are written in YAML. If YAML is new to you, read the YAML page first. These are the basics you’ll need:

  • Indentation matters: Use 2 spaces (not tabs) for each level.
  • Key-value pairs: key: value
  • Lists: Use hyphens (-) for array items.
  • Strings: Can be quoted or unquoted (quote when containing special characters).
  • Comments: Start with #

Two quoting rules apply to every OpenAPI file:

  • Quoted status codes: Write '200', not 200. OpenAPI expects response codes as strings, and YAML reads an unquoted 200 as a number.
  • Quoted $ref values: Write $ref: '#/components/schemas/Planet'. Without the quotes, YAML treats everything after the # as a comment.

Most OpenAPI files are built from five top-level keys:

KeyWhat it describes
openapiThe version of the OpenAPI Specification the file follows
infoThe API’s title, description, and version
serversThe base URLs where the API is hosted
pathsThe endpoints, with their HTTP methods, parameters, and responses
componentsReusable definitions such as schemas, parameters, and responses

openapi: 3.2.0 is the version of the OpenAPI Specification, not the version of your API. Your API’s version goes in info.version.

Here’s a complete example that uses all five keys:

openapi: 3.2.0
info:
title: My Planets API
description: A simple API for managing planetary data
version: 1.0.0
servers:
- url: https://api.space-research.com/v1
description: Production server
paths:
/planets:
get:
summary: Get all planets
responses:
'200':
description: Successful response
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Planet'
components:
schemas:
Planet:
type: object
required:
- id
- name
- system
properties:
id:
type: integer
example: 1
name:
type: string
example: "Earth"
system:
type: string
example: "Solar System"

The $ref line in the 200 response points to the Planet schema instead of repeating its definition. Read the reference #/components/schemas/Planet from left to right: # is the root of the current file, followed by the components key, the schemas key inside it, and the Planet schema.

Let’s walk through each section.


Provides basic metadata about your API. Always specify a clear title, a brief description, and a version number (use semantic versioning ↗ like 1.0.0).

info:
title: Your API Name
description: What your API does
version: 1.0.0
contact:
name: Your Name
email: your.email@example.com

Lists where your API is hosted. You can define multiple servers (e.g., production, staging, development).

servers:
- url: https://api.example.com/v1
description: Production server
- url: https://staging-api.example.com/v1
description: Staging server

This is the core of your specification. For each endpoint, define:

  • The URI path (e.g., /planets, /planets/{id})
  • HTTP methods (get, post, put, delete)
  • Parameters: path parameters (like {id}), query parameters (filters, pagination), and request bodies (for POST/PUT)
  • Responses: all possible HTTP status codes with their content types and schemas
paths:
/planets/{id}:
get:
summary: Get planet by ID
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
'200':
description: Planet found
content:
application/json:
schema:
$ref: '#/components/schemas/Planet'
'404':
description: Planet not found

The components section is where you define reusable pieces of your specification. Instead of repeating the same definition in every endpoint, you define it once here and reference it with $ref. It can contain:

  • schemas: Data models (e.g., Planet, ErrorResponse)
  • parameters: Query or path parameters (e.g., page, page_size)
  • responses: Common error responses (e.g., 400 Bad Request, 500 Internal Server Error)
  • securitySchemes: Authentication methods (e.g., API keys, JWT tokens)

See the OpenAPI Example page for a detailed explanation and a complete example using components.


Each snippet below goes under the paths key. The parts an operation needs depend on its HTTP method.

A GET operation uses query parameters for filtering and pagination. It has no request body.

/planets:
get:
summary: Get all planets
parameters:
- name: limit
in: query
schema:
type: integer
default: 10
responses:
'200':
description: List of planets

A POST operation needs a requestBody that describes the JSON the client sends.

/planets:
post:
summary: Create a new planet
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Planet'
responses:
'201':
description: Planet created
'422':
description: Invalid planet data

A PUT operation needs both a path parameter that identifies the resource and a requestBody that holds its new values.

/planets/{id}:
put:
summary: Update a planet
parameters:
- name: id
in: path
required: true
schema:
type: integer
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Planet'
responses:
'200':
description: Planet updated
'404':
description: Planet not found
'422':
description: Invalid planet data

A DELETE operation needs only the path parameter. A 204 response has no body, so it has no content.

/planets/{id}:
delete:
summary: Delete a planet
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
'204':
description: Planet deleted
'404':
description: Planet not found

OpenAPI supports various data types with validation rules:

properties:
age:
type: integer
minimum: 0
maximum: 150
email:
type: string
format: email
website:
type: string
format: uri
birth_date:
type: string
format: date
rating:
type: number
minimum: 1.0
maximum: 5.0
tags:
type: array
items:
type: string

Documenting authentication takes two steps:

  1. Define a security scheme under components.securitySchemes.
  2. Apply the scheme with the security key.

This example defines an API key sent in the X-API-Key header. The security key at the root of the file applies the scheme to every endpoint.

components:
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
security:
- ApiKeyAuth: []

The name under security must match the name defined under securitySchemes. The empty brackets [] are a list of scopes, which only OAuth2 uses. Leave the list empty for API keys and bearer tokens.


To protect a single endpoint instead of the whole API, put the security key inside that operation. This example requires a JWT only to create a planet.

components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
paths:
/planets:
post:
summary: Create a new planet
security:
- BearerAuth: []

Check your file while you write it, not only before submission. Paste the YAML into Swagger Editor ↗, which reports errors with line numbers and renders the interactive documentation next to your YAML.

The Resources and Tools page lists other editors.


  • Inconsistent indentation: Always use 2 spaces.
  • Missing colons: Every key needs a colon.
  • Incorrect list formatting: Use proper hyphen alignment.
  • Missing required fields: Always mark required fields in your schemas.
  • Inconsistent data types: Use the same type for the same data across endpoints.
  • Missing examples: Always provide realistic examples.
  • Incomplete error handling: Document all possible error scenarios.
  • Vague descriptions: Write clear, specific descriptions for endpoints and parameters.
  • Ignoring status codes: Document all possible HTTP response codes.
  • Non-RESTful patterns: Follow REST principles for consistency.
  • Overly complex schemas: Keep data models simple and focused.
  • Missing versioning: Always include API version information.
  • Inconsistent naming: Use snake_case for properties and kebab-case for paths.

  • Define your API’s basic info (title, version, description).
  • List your server URIs.
  • Document at least one GET endpoint.
  • Create schemas for your main data models.
  • Add request/response examples.
  • Test your specification in Swagger Editor.
  • All endpoints have clear descriptions and realistic examples.
  • Every response code is documented with appropriate schemas.
  • Data models are complete with proper types and validations.
  • Authentication requirements are clearly specified.
  • Error responses include meaningful error messages.
  • File validates without errors in VS Code extension.
  • Specification renders properly in OpenAPI Playground.
  • Generate documentation to share with others.