← ProgrammingBack to top

OpenAPI(Swagger)

1. Basic concepts

OpenAPI Specification (OAS) is a set of standard specifications for describing HTTP API, and API can be defined using the YAML or JSON format.

The OpenAPI document describes the interface path, request parameters, request body, response data, authentication method, data model, etc.

The difference between OpenAPI, Swagger and Schema

conceptDescription
OpenAPIThe standard specification for describing HTTP API
Swagger UIGenerate interactive API documents from OpenAPI documents
Swagger EditorEdit and validate OpenAPI documents
Swagger CodegenGenerate client or server code according to OpenAPI documentation
SchemaSchema definition describing API request, response and data structure

OpenAPI itself is not a API framework, nor is it responsible for executing HTTP requests, but rather provides a machine-readable API contract.

Typical workflow:

Django REST Framework
         ↓
drf-spectacular
         ↓
OpenAPI Schema (YAML / JSON)
         ↓
    ┌────┴───────┐
    ↓            ↓
Swagger UI      Orval
    ↓            ↓
API Documentation       TypeScript Type
              API Client / Hooks

In this way, the front and back ends can share the same API definition, reducing the problem of interface field inconsistency.

2. OpenAPI document structure

Main objects in a OpenAPI document:

objectfunctionIs it necessary
OpenAPI ObjectThe root object containing the entire API definitionYes
Info ObjectAPI name, version, description and other metadataYes
Paths ObjectAPI paths and HTTP operationsYes
Servers ObjectAPI server addressesNo
Components ObjectReusable Schema, parameters, responses, and moreNo
Tags ObjectLogical grouping of API operationsNo
ExternalDocs ObjectLinks to external documentationNo
Security Requirement ObjectStatement of security certification requirements for APINo

Note: security is a field in the OpenAPI root object or Operation Object, not an independent top-level object name at the same level as paths and components.

Minimal documentation for OpenAPI 3.0:

openapi: 3.0.3

info:
  title: Example API
  version: 1.0.0

paths: {}

OpenAPI Object

Complete structure example:

openapi: 3.0.3

info:
  title: Example API
  description: Example REST API
  version: 1.0.0

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

tags:
  - name: users
    description: User management

paths:
  /users:
    get:
      tags:
        - users
      summary: Get users
      operationId: listUsers
      responses:
        "200":
          description: Successful response

components:
  schemas: {}

security: []

Among them, openapi represents the OpenAPI specification version, and info.version represents the version of API itself.

3. Info Object

info defines the basic information of API.

info:
  title: Example API
  description: API documentation example
  version: 1.0.0

  termsOfService: https://example.com/terms

  contact:
    name: API Developer
    url: https://example.com
    email: developer@example.com

  license:
    name: Apache 2.0
    url: https://www.apache.org/licenses/LICENSE-2.0
Fieldfunction
titleAPI title
descriptionAPI description, supports Markdown
versionAPI version
termsOfServiceTerms of Service
contactContact information
licenseLicense information

Where title and version are required fields.

4. Servers Object

servers describes the server address of API.

Multiple servers can be specified:

servers:
  - url: https://dev.example.com/api/v1
    description: Development

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

  - url: https://api.example.com/api/v1
    description: Production

Use server variables

servers:
  - url: https://{environment}.example.com/api/v{version}
    variables:
      environment:
        default: api
        enum:
          - api
          - dev
          - staging

      version:
        default: "1"
        enum:
          - "1"
          - "2"

variables allows the use of variables to define server addresses to avoid repeatedly writing similar configurations for different environments.

5. Paths Object and Operation Object

paths defines paths to API, each path containing one or more HTTP operations.

For example:

paths:
  /users:
    get:
      summary: Get users
      operationId: listUsers
      responses:
        "200":
          description: Success

    post:
      summary: Create user
      operationId: createUser
      responses:
        "201":
          description: Created

  /users/{userId}:
    get:
      summary: Get user
      operationId: getUser
      parameters:
        - name: userId
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: Success

Common fields of Operation Object

Fieldfunction
tagsInterface grouping
summaryInterface short description
descriptionInterface detailed description
operationIdInterface unique identifier
parametersPath, Query, Header, Cookie parameters
requestBodyHTTP request body
responsesHTTP response definition
securityOverride global authentication requirements
deprecatedIndicate whether an operation is deprecated
serversOverride server addresses
callbacksDescribe callbacks initiated by the API provider
externalDocsexternal documentation

where responses is a required field for Operation Object.

operationId

operationId: getUserProfile

operationId must remain unique throughout the OpenAPI document.

Code generation tools often use this to generate function names.

For example, Orval might be based on:

operationId: getUserProfile

Generate:

getUserProfile();
useGetUserProfile();

The specific generated results depend on the Orval configuration.

Therefore, it is recommended to use operationId, which is stable, clear and consistent with programming naming conventions.

6. Parameters Object

parameters is used to describe request parameters.

There are four positions:

inParameter positionExample
pathURL path/users/{userId}
queryquery string?page=2
headerHTTP HeaderX-Request-ID
cookieCookiesessionid

Path Parameter

parameters:
  - name: userId
    in: path
    required: true
    description: User ID
    schema:
      type: integer

For in: path, required must be true.

Query Parameter

parameters:
  - name: page
    in: query
    required: false
    schema:
      type: integer
      minimum: 1
      default: 1

  - name: search
    in: query
    required: false
    schema:
      type: string

Corresponding request:

GET /users?page=2&search=Alice

Parameter Common fields

Fieldfunction
nameParameter name
inParameter location
descriptionParameter description
requiredIs it required?
deprecatedWhether to deprecate
schemaParameter data structure and verification constraints
exampleParameter example values
styleParameter serialization method
explodeControl how array or object parameters are expanded
allowEmptyValueWhether to allow null values, mainly for the Query parameter

Serialization of array parameters

parameters:
  - name: ids
    in: query
    style: form
    explode: true
    schema:
      type: array
      items:
        type: integer

Corresponds to:

GET /users?ids=1&ids=2&ids=3

If set:

style: form
explode: false

Then it is usually serialized as:

GET /users?ids=1,2,3

7. Request Body Object

requestBody describes the data sent by the client.

Usually used for POST, PUT, PATCH and other requests.

requestBody:
  required: true
  description: User information
  content:
    application/json:
      schema:
        type: object
        required:
          - username
          - email
        properties:
          username:
            type: string
          email:
            type: string
            format: email
          password:
            type: string
            format: password
      example:
        username: johndoe
        email: john@example.com
        password: example-password

The difference between parameters and requestBody

compareparametersrequestBody
functionDescribe independent request parametersDescribe the request body
locationpath/query/header/cookieHTTP Body
data structureUsually defined for a single parameter SchemaComplete objects can be defined
Common usesGET query, path parametersPOST, PUT, PATCH requests

Note: HTTP does not absolutely prohibit GET requests from carrying Body, but GET Body does not have universally defined request semantics; OpenAPI 3.0 also does not support defining GET requestBody in a conventional way.

Multiple media types

requestBody:
  content:
    application/json:
      schema:
        $ref: "#/components/schemas/User"

    application/x-www-form-urlencoded:
      schema:
        $ref: "#/components/schemas/User"

content can define multiple media types, including JSON, form data and file upload.

8. Responses Object

responses describes the response of API under different HTTP status codes.

responses:
  "200":
    description: Successful response
    content:
      application/json:
        schema:
          $ref: "#/components/schemas/User"

  "400":
    description: Invalid request
    content:
      application/json:
        schema:
          $ref: "#/components/schemas/Error"

  "404":
    description: User not found

  "500":
    description: Internal server error

Common status codes:

status codemeaning
200Request successful
201Resource created successfully
202Request accepted, may be processed asynchronously
204Request successful, no response body
400Request parameter error
401Missing valid authentication credentials
403Forbidden access
404Resource does not exist
409Resource status conflict
422The request content cannot be processed
500Server internal error

unresponsive body

For 204 No Content:

responses:
  "204":
    description: Successfully deleted

There is no need to define content.

Default response

responses:
  "200":
    description: Success

  default:
    description: Unexpected error

default can describe other response situations not listed separately.

9. Components Object

components is the reusable component container of OpenAPI.

Mainly includes:

Fieldfunction
schemasReusable data model
parametersReusable request parameters
responsesReusable responses
requestBodiesReusable request body
headersReusable response header definitions
examplesReusable examples
securitySchemesAuthentication mechanism definition
linksAPI Relationship between operations
callbacksReusable callbacks

Definition Schema

components:
  schemas:
    User:
      type: object
      required:
        - id
        - username
      properties:
        id:
          type: integer
        username:
          type: string
        email:
          type: string
          format: email

Define reusable parameters

components:
  parameters:
    PageParam:
      name: page
      in: query
      schema:
        type: integer
        minimum: 1
        default: 1

Define reusable responses

components:
  responses:
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            type: object
            properties:
              detail:
                type: string

10. $ref: component reference

$ref is used to reference already defined components to reduce duplicate code.

For example:

paths:
  /users:
    get:
      operationId: listUsers
      parameters:
        - $ref: "#/components/parameters/PageParam"
      responses:
        "404":
          $ref: "#/components/responses/NotFound"

Schema Quote:

schema:
  $ref: "#/components/schemas/User"

Reference path:

#/components/schemas/User

Meaning is quoted from the current document:

components
  └── schemas
        └── User

$ref also supports referencing definitions in external files or URL.

In OpenAPI 3.0, other sibling fields of Reference Object are usually ignored, so it is not recommended to override the original definition by adding fields such as description directly next to $ref.

11. Schema Object: Data model

Schema Object is used to describe data types, fields and validation rules.

OpenAPI 3.0's Schema is based on an extended subset of JSON Schema, rather than fully supporting all JSON Schema keywords.

Common data types

TypemeaningCommonly used format
stringstringdate、date-time、email、uuid、binary
integerintegerint32、int64
numbernumerical valuefloat、double
booleanBoolean value—
arrayarray—
objectobject—

format is a further description of the basic type, and the specific verification behavior depends on the tool used.

Complete Schema example

components:
  schemas:
    Product:
      type: object
      required:
        - id
        - name
        - price
      properties:
        id:
          type: integer
          format: int64
          readOnly: true

        name:
          type: string
          minLength: 1
          maxLength: 100

        description:
          type: string
          nullable: true

        price:
          type: number
          minimum: 0

        category:
          type: string
          enum:
            - electronics
            - books
            - clothing

        tags:
          type: array
          items:
            type: string

        metadata:
          type: object
          additionalProperties: true

Common validation fields

FieldDescription
requiredRequired attribute list
nullableIs null (OpenAPI 3.0) allowed?
defaultDefault value description
enumLimit allowed values
minimum / maximumNumeric range
minLength / maxLengthString length limit
patternRegular expression constraints
minItems / maxItemsLimit on the number of array elements
uniqueItemsAre array elements unique?
additionalPropertiesWhether to allow additional object properties
readOnlyread-only fields
writeOnlywrite-only fields
deprecatedTag field is deprecated

The difference between required and nullable

type: object
required:
  - name
properties:
  name:
    type: string
    nullable: true
  • required: This field must exist in the object.
  • nullable: Allowed field value is null.

Therefore, this example requires that name be provided, but allows the value null.

Fields not written in the required list mean they can be omitted and do not automatically mean null is allowed.

12. allOf / oneOf / anyOf

OpenAPI supports building complex data structures using combining keywords.

Keywordsmeaning
allOfMust satisfy all Schema
oneOfMust satisfy exactly one Schema
anyOfMeet at least one Schema
notDoes not meet specified Schema

allOf: Combination Schema

components:
  schemas:
    Pet:
      type: object
      required:
        - name
      properties:
        name:
          type: string

    Dog:
      allOf:
        - $ref: "#/components/schemas/Pet"
        - type: object
          properties:
            breed:
              type: string

Dog satisfies both Pet and the new field constraints.

allOf is often used to compose data models, but does not imply object-oriented inheritance at the programming language level.

oneOf: Multiple possible data models

schema:
  oneOf:
    - $ref: "#/components/schemas/Dog"
    - $ref: "#/components/schemas/Cat"

Indicates that the data must match exactly one of Schema.

If you need to distinguish between different object types, you can use it in combination with discriminator.

13. Security Schemes

OpenAPI uses components.securitySchemes to define the authentication mechanism, and then uses security to declare the authentication method required by the interface.

Bearer Token (commonly used in JWT)

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

security:
  - BearerAuth: []

Corresponding to HTTP request:

Authorization: Bearer <token>

bearerFormat: JWT is primarily a documentation hint and does not mean that OpenAPI automatically validates JWT.

API Key

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
components:
  securitySchemes:
    SessionAuth:
      type: apiKey
      in: cookie
      name: sessionid

This way describes the credentials passed via Cookie, but the actual Session validation is still done by the backend.

CSRF Token also does not gain protection capabilities simply by defining securitySchemes.

Override authentication for a single interface

paths:
  /public:
    get:
      security: []
      responses:
        "200":
          description: Success

security: [] indicates that the global security requirements inherited by this operation are removed.

14. Tags and ExternalDocs

Tags: Interface grouping

tags:
  - name: users
    description: User management

  - name: products
    description: Product management

paths:
  /users:
    get:
      tags:
        - users
      responses:
        "200":
          description: Success

Tags is mainly used for interface classification of document tools such as Swagger UI.

ExternalDocs: external document

externalDocs:
  description: Additional API documentation
  url: https://example.com/docs

External documentation information can be provided at the top level, in operations, or in partial Schema definitions.

15. File upload: multipart/form-data

File uploads usually use multipart/form-data.

paths:
  /users/avatar:
    post:
      summary: Upload avatar
      operationId: uploadAvatar

      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - file
              properties:
                file:
                  type: string
                  format: binary

      responses:
        "200":
          description: Upload successful

Key points:

type: string
format: binary

Represents the binary file field.

For Django REST Framework, this can usually be combined with:

from rest_framework.parsers import MultiPartParser

Handle upload requests.

16. drf-spectacular and Django REST Framework

drf-spectacular can automatically generate OpenAPI Schema based on the View, Serializer, URL and other information of DRF.

Basic configuration

# settings.py

INSTALLED_APPS = [
    "rest_framework",
    "drf_spectacular",
]

REST_FRAMEWORK = {
    "DEFAULT_SCHEMA_CLASS":
        "drf_spectacular.openapi.AutoSchema",
}

SPECTACULAR_SETTINGS = {
    "TITLE": "Example API",
    "DESCRIPTION": "REST API documentation",
    "VERSION": "1.0.0",
}

Configure API document routing

# urls.py

from django.urls import path
from drf_spectacular.views import (
    SpectacularAPIView,
    SpectacularSwaggerView,
    SpectacularRedocView,
)

urlpatterns = [
    path(
        "api/schema/",
        SpectacularAPIView.as_view(),
        name="schema",
    ),
    path(
        "api/docs/",
        SpectacularSwaggerView.as_view(
            url_name="schema"
        ),
        name="swagger-ui",
    ),
    path(
        "api/redoc/",
        SpectacularRedocView.as_view(
            url_name="schema"
        ),
        name="redoc",
    ),
]

These routes are used for:

  • /api/schema/: Get OpenAPI Schema.
  • /api/docs/: View Swagger UI.
  • /api/redoc/: View ReDoc documentation.

extend_schema

@extend_schema is used to supplement or overwrite the automatically generated OpenAPI information.

from drf_spectacular.utils import (
    extend_schema,
    OpenApiParameter,
    OpenApiTypes,
)
from rest_framework.views import APIView
from rest_framework.response import Response


class UserView(APIView):

    @extend_schema(
        tags=["Users"],
        summary="Get user",
        operation_id="getUser",
        parameters=[
            OpenApiParameter(
                name="user_id",
                type=OpenApiTypes.INT,
                location=OpenApiParameter.QUERY,
                required=True,
            )
        ],
        responses={200: UserSerializer},
    )
    def get(self, request):
        ...

Parameters, request body and response body

In extend_schema:

parametersCorresponds to OpenAPI
parametersParameter Object
requestRequest Body Object
responsesResponses Object
operation_idoperationId
summarysummary
descriptiondescription
tagstags
deprecateddeprecated

For example:

@extend_schema(
    operation_id="createUser",
    request=UserCreateSerializer,
    responses={
        201: UserResponseSerializer,
        400: ErrorSerializer,
    },
)
def post(self, request):
    ...

extend_schema_view

For cases where Schema needs to be specified for multiple methods at the class level:

from drf_spectacular.utils import (
    extend_schema,
    extend_schema_view,
)


@extend_schema_view(
    get=extend_schema(
        operation_id="listUsers",
        responses=UserSerializer(many=True),
    ),
    post=extend_schema(
        operation_id="createUser",
        request=UserCreateSerializer,
        responses={201: UserSerializer},
    ),
)
class UserView(APIView):
    ...

extend_schema_view is suitable for unified description of multiple operations in a View.

Generate OpenAPI file

python manage.py spectacular \
    --file schema.yaml \
    --validate

The generated schema.yaml can be used for:

  • Swagger UI
  • ReDoc
  • Orval
  • OpenAPI Generator
  • API Schema check

It should be noted that the successful verification of Schema can only mean that the document basically complies with the specifications, and it cannot guarantee that the actual behavior of API is completely consistent with the document.

17. OpenAPI and front-end code generation

For React + TypeScript projects, you can use Orval to automatically generate API Client and type definitions based on OpenAPI Schema.

Django Serializer
       ↓
drf-spectacular
       ↓
OpenAPI Schema
       ↓
Orval
       ↓
TypeScript Types
Axios Functions
TanStack Query Hooks

For example backend:

@extend_schema(
    operation_id="getUser",
    responses=UserSerializer,
)

The front end may generate:

getUser();
useGetUser();

The main value of this approach is:

  • Reduce the repeated definition of interface types at the front and back ends.
  • Improve request and response type safety.
  • Simplify maintenance of API Client.
  • Reduce the risk of inconsistent field naming.

But please note: OpenAPI Schema is just an interface contract, and the generated TypeScript type does not guarantee that the server will return data that conforms to Schema when it is running.

Therefore, data validation, testing, and Schema accuracy on the backend remain important.

18. The difference between OpenAPI 3.0 and 3.1

OpenAPI 3.1 makes important adjustments to Schema support to make it more consistent with JSON Schema Draft 2020-12.

FeaturesOpenAPI 3.0OpenAPI 3.1
Schema BasicsJSON Schema extended subsetAlignment JSON Schema 2020-12
nullableUse nullable: trueUsually a union type is used to represent null
JSON Schema keywordLimited supportSupport more complete
Schema CompatibilityNeed to pay attention to the unique constraints of OpenAPICloser to standard JSON Schema

OpenAPI 3.0:

type: string
nullable: true

OpenAPI 3.1:

type:
  - string
  - "null"

In addition, in OpenAPI 3.1, related mechanisms such as $ref have also been further improved.

In actual development, the OpenAPI version should be selected based on the compatibility of the documentation tool and code generator used, and it is not necessarily necessary to upgrade to the latest version immediately.

Summary

The core content of OpenAPI can be divided into four parts:

Classificationfocus
Document structureOpenAPI、Info、Servers、Paths
Interface definitionOperation、Parameters、RequestBody、Responses
data modelSchema、Components、$ref、allOf、oneOf
engineering practiceSecuritySchemes、Swagger UI、drf-spectacular、Orval

What needs to be mastered most is:

  1. paths and Operation Object: Describe the interface.
  2. parameters and requestBody: Description input.
  3. responses and schemas: Describe the output and data structure.
  4. components and $ref: Implement component reuse.
  5. operationId: Support stable client code generation.
  6. securitySchemes: Describes interface certification requirements.

For the development of Django + DRF, it is recommended to use Serializer as the main data structure definition, then automatically generate OpenAPI Schema through drf-spectacular, and finally give it to Swagger UI and Orval for use.


Reference documentation