← プログラミングページの先頭へ

OpenAPI(Swagger)

1. 基本的な考え方

OpenAPI Specification (OAS) は HTTP API を記述するための標準仕様のセットであり、API は YAML または JSON 形式を使用して定義できます。

OpenAPI ドキュメントには、インターフェイス パス、リクエスト パラメーター、リクエスト本文、応答データ、認証方法、データ モデルなどが記述されています。

OpenAPI、Swagger、Schemaの違い

コンセプト説明
OpenAPIHTTP APIを記載した標準仕様
Swagger UIOpenAPI ドキュメントからインタラクティブな API ドキュメントを生成
Swagger EditorOpenAPI ドキュメントの編集と検証
Swagger CodegenOpenAPI ドキュメントに従ってクライアントまたはサーバー コードを生成します。
SchemaAPI リクエスト、レスポンス、データ構造を記述するスキーマ定義

OpenAPI 自体は API フレームワークではなく、HTTP リクエストの実行も担当しませんが、機械可読な API コントラクトを提供します。

一般的なワークフロー:

Django REST Framework
         ↓
drf-spectacular
         ↓
OpenAPI Schema (YAML / JSON)
         ↓
    ┌────┴───────┐
    ↓            ↓
Swagger UI      Orval
    ↓            ↓
API ドキュメント       TypeScript タイプ
              API Client / Hooks

このようにして、フロントエンドとバックエンドが同じ API 定義を共有できるため、インターフェイス フィールドの不一致の問題が軽減されます。

2. OpenAPI ドキュメント構造

OpenAPI ドキュメントの主なオブジェクト:

オブジェクト機能必要ですか
OpenAPI ObjectAPI 定義全体を含むルート オブジェクトはい
Info ObjectAPI の名前、バージョン、説明、その他のメタデータはい
Paths ObjectAPI パスと HTTP 操作はい
Servers ObjectAPI サーバーアドレスいいえ
Components Object再利用可能なSchema、パラメータ、応答などいいえ
Tags Objectインターフェイスを論理的にグループ化するいいえ
ExternalDocs Object外部ドキュメントへのリンクいいえ
Security Requirement ObjectAPI のセキュリティ認証要件に関する声明いいえ

注: security は、OpenAPI ルート オブジェクトまたは Operation Object 内のフィールドであり、paths および components と同じレベルにある独立したトップレベル オブジェクト名ではありません。

OpenAPI 3.0 の最小限のドキュメント:

openapi: 3.0.3

info:
  title: Example API
  version: 1.0.0

paths: {}

OpenAPI Object

完全な構造例:

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: []

このうち、openapi は OpenAPI 仕様のバージョンを表し、info.version は API 自体のバージョンを表します。

3. Info Object

infoは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
フィールド機能
titleAPIタイトル
descriptionAPI の説明、Markdown をサポート
versionAPIバージョン
termsOfService利用規約
contact連絡先情報
licenseライセンス情報

title と version は必須フィールドです。

4. Servers Object

servers は、API のサーバー アドレスを記述します。

複数のサーバーを指定できます。

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

サーバー変数を使用する

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

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

variables では、変数を使用してサーバー アドレスを定義できるため、異なる環境に対して同様の構成を繰り返し記述する必要がなくなります。

5. Paths ObjectとOperation Object

paths は API へのパスを定義し、各パスには 1 つ以上の HTTP 操作が含まれます。

たとえば:

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

Operation Objectの共通フィールド

フィールド機能
tagsインターフェースのグループ化
summaryインターフェースの簡単な説明
descriptionインターフェースの詳細説明
operationIdインターフェースの一意の識別子
parametersPath、Query、Header、Cookieパラメータ
requestBodyHTTP リクエストボディ
responsesHTTP 応答定義
securityグローバルな認証要件をカバー
deprecatedインターフェイスが非推奨かどうかをマークする
serversサーバーアドレスを上書きする
callbacksAPI プロバイダーによって開始されるコールバックについて説明します
externalDocs外部ドキュメント

ここで、responses は Operation Object の必須フィールドです。

operationId

operationId: getUserProfile

operationId は、OpenAPI ドキュメント全体で一意である必要があります。

コード生成ツールは、多くの場合、これを使用して関数名を生成します。

たとえば、Orval は次のものに基づいている可能性があります。

operationId: getUserProfile

生成:

getUserProfile();
useGetUserProfile();

生成される特定の結果は、Orval 構成によって異なります。

したがって、安定していて明確で、プログラミングの命名規則と一致している operationId を使用することをお勧めします。

6. Parameters Object

parameters はリクエストパラメータを記述するために使用されます。

次の 4 つのポジションがあります。

inパラメータの位置例
pathURL パス/users/{userId}
queryクエリ文字列?page=2
headerHTTP HeaderX-Request-ID
cookieCookiesessionid

Path Parameter

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

in: path の場合、required は 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

対応するリクエスト:

GET /users?page=2&search=Alice

Parameter 共通フィールド

フィールド機能
nameパラメータ名
inパラメータの場所
descriptionパラメータの説明
required必要ですか?
deprecated廃止するかどうか
schemaパラメータのデータ構造と検証制約
exampleパラメータの値の例
styleパラメータのシリアル化方法
explode配列またはオブジェクトのパラメータを展開する方法を制御します
allowEmptyValue主に Query パラメータに対して NULL 値を許可するかどうか

配列パラメータのシリアル化

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

以下に対応します:

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

設定されている場合:

style: form
explode: false

その後、通常は次のようにシリアル化されます。

GET /users?ids=1,2,3

7. Request Body Object

requestBody は、クライアントによって送信されるデータを記述します。

通常、POST、PUT、PATCH およびその他のリクエストに使用されます。

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

parametersとrequestBodyの違い

比較するparametersrequestBody
機能独立したリクエストパラメータを記述するリクエストボディを記述します
場所path/query/header/cookieHTTP Body
データ構造通常は単一のパラメータ Schema に対して定義されます完全なオブジェクトを定義可能
一般的な用途GET クエリ、パスパラメータPOST、PUT、PATCH リクエスト

注: HTTP は、GET リクエストが Body を送信することを絶対に禁止するわけではありませんが、GET Body には普遍的に定義されたリクエスト セマンティクスがありません。 OpenAPI 3.0 は、従来の方法での GET requestBody の定義もサポートしていません。

複数のメディアタイプ

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

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

content では、JSON、フォーム データ、ファイル アップロードなど、複数のメディア タイプを定義できます。

8. Responses Object

responses は、さまざまな HTTP ステータス コードでの API の応答を記述します。

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

一般的なステータス コード:

ステータスコード意味
200リクエストは成功しました
201リソースが正常に作成されました
202リクエストは受け入れられ、非同期的に処理される可能性があります
204リクエストは成功しましたが、レスポンスボディはありません
400リクエストパラメータエラー
401有効な認証資格情報がありません
403アクセス禁止
404リソースが存在しません
409リソースステータスの競合
422リクエストの内容を処理できません
500サーバー内部エラー

反応しない体

204 No Contentの場合:

responses:
  "204":
    description: Successfully deleted

content を定義する必要はありません。

デフォルトの応答

responses:
  "200":
    description: Success

  default:
    description: Unexpected error

default では、個別にリストされていない他の応答状況を説明できます。

9. Components Object

components は、OpenAPI の再利用可能なコンポーネント コンテナです。

主に以下が含まれます:

フィールド機能
schemas再利用可能なデータモデル
parameters再利用可能なリクエストパラメータ
responses再利用可能な応答
requestBodies再利用可能なリクエストボディ
headers再利用可能な応答ヘッダー定義
examples再利用可能な例
securitySchemes認証メカニズムの定義
linksAPI 操作間の関係
callbacks再利用可能なコールバック

定義 Schema

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

再利用可能なパラメータを定義する

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

再利用可能な応答を定義する

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

10. $ref: コンポーネントリファレンス

$ref は、重複するコードを減らすために、すでに定義されているコンポーネントを参照するために使用されます。

たとえば:

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

Schema 引用:

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

参照パス:

#/components/schemas/User

意味は現在の文書から引用されています。

components
  └── schemas
        └── User

$ref は、外部ファイルまたは URL の定義の参照もサポートしています。

OpenAPI 3.0 では、Reference Object の他の兄弟フィールドは通常無視されるため、$ref のすぐ隣に description などのフィールドを追加して元の定義をオーバーライドすることはお勧めできません。

11. Schema Object: データモデル

Schema Object は、データ型、フィールド、および検証ルールを記述するために使用されます。

OpenAPI 3.0 の Schema は、すべての JSON Schema キーワードを完全にサポートするのではなく、JSON Schema の拡張サブセットに基づいています。

一般的なデータ型

タイプ意味よく使われるformat
string文字列date、date-time、email、uuid、binary
integer整数int32、int64
number数値float、double
booleanブール値—
array配列—
objectオブジェクト—

format は基本タイプの詳細な説明であり、具体的な検証動作は使用するツールによって異なります。

Schema の完全な例

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

共通の検証フィールド

フィールド説明
required必須の属性リスト
nullablenull (OpenAPI 3.0) は使用できますか?
defaultデフォルト値の説明
enum許可される値を制限する
minimum / maximum数値範囲
minLength / maxLength文字列の長さの制限
pattern正規表現の制約
minItems / maxItems配列要素数の制限
uniqueItems配列要素は一意ですか?
additionalProperties追加のオブジェクト プロパティを許可するかどうか
readOnly読み取り専用フィールド
writeOnly書き込み専用フィールド
deprecatedタグフィールドは非推奨になりました

requiredとnullableの違い

type: object
required:
  - name
properties:
  name:
    type: string
    nullable: true
  • required: このフィールドはオブジェクト内に存在する必要があります。
  • nullable: 許可されるフィールド値は null です。

したがって、この例では name を指定する必要がありますが、値 null を許可します。

required リストに記載されていないフィールドは省略できることを意味し、自動的に null が許可されることを意味するものではありません。

12. allOf / oneOf / anyOf

OpenAPI は、キーワードを組み合わせて複雑なデータ構造を構築することをサポートします。

キーワード意味
allOfSchema をすべて満たす必要があります
oneOfSchema を 1 つだけ満たす必要があります
anyOf少なくとも 1 人の Schema に会います
not指定された Schema を満たしていません

allOf: 組み合わせ 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 は、Pet と新しいフィールド制約の両方を満たします。

allOf はデータ モデルを構成するためによく使用されますが、プログラミング言語レベルでのオブジェクト指向の継承を意味するものではありません。

oneOf: 複数の可能なデータ モデル

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

データが Schema のいずれかに正確に一致する必要があることを示します。

異なるオブジェクトタイプを区別する必要がある場合は、discriminator と組み合わせて使用​​できます。

13. Security Schemes

OpenAPI は、components.securitySchemes を使用して認証メカニズムを定義し、次に security を使用してインターフェイスに必要な認証方法を宣言します。

Bearer Token(JWTと共用)

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

security:
  - BearerAuth: []

HTTP リクエストに対応:

Authorization: Bearer <token>

bearerFormat: JWT は主にドキュメントのヒントであり、OpenAPI が JWT を自動的に検証することを意味するものではありません。

API Key

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

この方法では、Cookie 経由で渡される資格情報が記述されていますが、実際の Session 検証は依然としてバックエンドによって行われます。

また、CSRF Token は、securitySchemes を定義するだけでは保護機能を獲得しません。

単一インターフェースの認証をオーバーライドする

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

security: [] は、この操作によって継承されたグローバル セキュリティ要件が削除されることを示します。

14. TagsとExternalDocs

Tags: インターフェースのグループ化

tags:
  - name: users
    description: User management

  - name: products
    description: Product management

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

Tags は主に Swagger UI などのドキュメント ツールのインターフェイス分類に使用されます。

ExternalDocs: 外部ドキュメント

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

外部文書情報は、最上位レベル、操作内、または部分的な Schema 定義で提供できます。

15. ファイルアップロード: multipart/form-data

ファイルのアップロードには通常、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

重要なポイント:

type: string
format: binary

バイナリファイルフィールドを表します。

Django REST Framework の場合、これは通常、次のものと組み合わせることができます。

from rest_framework.parsers import MultiPartParser

アップロードリクエストを処理します。

16. drf-spectacularとDjango REST Framework

drf-spectacular は、View、Serializer、URL および DRF のその他の情報に基づいて、OpenAPI Schema を自動的に生成できます。

基本構成

# 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",
}

API ドキュメント ルーティングを構成する

# 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",
    ),
]

これらのルートは次の目的で使用されます。

  • /api/schema/: OpenAPI Schema を取得します。
  • /api/docs/: Swagger UI を表示します。
  • /api/redoc/: ReDoc のドキュメントを表示します。

extend_schema

@extend_schema は、自動生成された OpenAPI 情報を補足または上書きするために使用されます。

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):
        ...

パラメータ、リクエストボディ、レスポンスボディ

extend_schema:

パラメータOpenAPIに対応
parametersParameter Object
requestRequest Body Object
responsesResponses Object
operation_idoperationId
summarysummary
descriptiondescription
tagstags
deprecateddeprecated

たとえば:

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

extend_schema_view

クラス レベルで複数のメソッドに対して Schema を指定する必要がある場合:

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は、Viewで複数の演算を統一的に記述するのに適しています。

OpenAPIファイルを生成する

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

生成された schema.yaml は次の用途に使用できます。

  • Swagger UI
  • ReDoc
  • Orval
  • OpenAPI Generator
  • API Schemaチェック

Schema の検証が成功したということは、ドキュメントが基本的に仕様に準拠していることを意味するだけであり、API の実際の動作がドキュメントと完全に一致することを保証するものではないことに注意してください。

17. OpenAPI とフロントエンド コード生成

React + TypeScript プロジェクトの場合、Orval を使用して、OpenAPI Schema に基づいて API Client と型定義を自動的に生成できます。

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

バックエンドの例:

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

フロントエンドは以下を生成する場合があります。

getUser();
useGetUser();

このアプローチの主な価値は次のとおりです。

  • フロントエンドとバックエンドでのインターフェイス タイプの繰り返し定義を減らします。
  • リクエストとレスポンスのタイプの安全性を向上させます。
  • API Clientのメンテナンスを簡素化します。
  • 一貫性のないフィールド名が発生するリスクを軽減します。

ただし、注意してください: OpenAPI Schema は単なるインターフェイス コントラクトであり、生成された TypeScript 型は、サーバーが実行中に Schema に準拠するデータを返すことを保証しません。

したがって、バックエンドでのデータの検証、テスト、および Schema の精度は依然として重要です。

18. OpenAPI 3.0と3.1の違い

OpenAPI 3.1 では、JSON Schema Draft 2020-12 との一貫性を高めるために、Schema のサポートに重要な調整が行われています。

特長OpenAPI 3.0OpenAPI 3.1
Schemaの基本JSON Schema 拡張サブセットアライメント JSON Schema 2020-12
nullablenullable: trueを使用してください通常、null を表すには共用体型が使用されます。
JSON Schema キーワード限定的なサポートサポートがさらに充実
Schemaの互換性OpenAPIの固有制約に注意が必要標準のJSON Schemaに近い

OpenAPI 3.0:

type: string
nullable: true

OpenAPI 3.1:

type:
  - string
  - "null"

また、OpenAPI 3.1では、$refなどの関連機構もさらに改善されました。

実際の開発においては、使用するドキュメントツールやコードジェネレータとの互換性を考慮して OpenAPI バージョンを選択する必要があり、必ずしもすぐに最新バージョンにアップグレードする必要はありません。

概要

OpenAPI の中心的な内容は 4 つの部分に分けることができます。

分類フォーカス
文書構造OpenAPI、Info、Servers、Paths
インターフェースの定義Operation、Parameters、RequestBody、Responses
データモデルSchema、Components、$ref、allOf、oneOf
エンジニアリングの実践SecuritySchemes、Swagger UI、drf-spectacular、Orval

最も習得する必要があるのは次のとおりです。

  1. paths および Operation Object: インターフェースについて説明します。
  2. parameters および requestBody: 説明入力。
  3. responses および schemas: 出力とデータ構造を説明します。
  4. components および $ref: コンポーネントの再利用を実装します。
  5. operationId: 安定したクライアント コード生成をサポートします。
  6. securitySchemes: インターフェイスの認証要件について説明します。

Django + DRF 開発の場合は、メインのデータ構造定義として Serializer を使用し、OpenAPI Schema から drf-spectacular までを自動的に生成し、最後にそれを Swagger UI および Orval に渡して使用することをお勧めします。


参考資料