2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Dockerを使ったSwaggerのコンテナ環境を構築してAPI仕様書を自動生成しよう!

Last updated at Posted at 2023-08-19

概要

APIの検証、ドキュメント化およびドキュメント化にSwaggerを使っているプロダクトが多いかと思います
今回はDockerを使ってSwagger用の環境を構築する方法について解説していきます

前提

  • 今回はバックエンドのフレームワークにDjangoを使用します
    • 後述するCORSの設定に関してましてはDjangoの設定ファイル内の記載方法を解説していますがSwaggerのドキュメントの記載方法は使用しているフレームワークが違っていても参考になるかと思います
  • Dockerとdocker-composeに関する基礎的な知識を有していること

ファイル構成

tree
・
├── application # アプリケーションを格納する専用フォルダ
│   └── project
    │   └── settings.py # Djangoの設定ファイル
├── doc
│   └── openapi.yml
└── docker-compose.yml

Swagger用のコンテナの設定

今回はdocker-compose.ymlを使ってSwaggerのコンテナを作成します

docker-compose.yml
  # swaggerの設定
  doc:
    image: swaggerapi/swagger-ui
    container_name: doc
    # 後述するdocフォルダ内のAPI仕様書(openapi.yml)を/usr/share/nginx/html/openapi.ymlへマウントする
    volumes:
      - ./doc/openapi.yml:/usr/share/nginx/html/openapi.yml
    # openapi.ymlを指定
    environment:
      API_URL: openapi.yml
    ports:
      - 9000:8080

API仕様書(openapi.yml)の作成

openapi.ymlを作成します

doc/openapi.yml
# https://swagger.io/specification/
# openapiのバージョン。今回は
openapi: 3.1.0
# APIに関するメタデータ
info:
    # プロジェクト名を記載
  title: project
  description: |-
    # プロジェクトの詳細

  version: 1.0.0
# Djangoは8000ポートを使用しているので今回は以下のように指定
servers:
  - url: http://localhost:8000/

Corsの設定

アプリケーション側とSwagger側のオリジンが違うためSwaggerのコンテナからAPIへリクエストを送るとCORSエラーが発生してしまいます
スクリーンショット 2023-08-19 9.51.17.png

そのため、Swagger側のオリジンを許可するようCORSの設定を行います

project/settings.py
INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "rest_framework",
    "application.apps.ApplicationConfig",
    # corsheadersをINSTALLED_APPSに追加
    "corsheaders",
]

# 自身以外のオリジンのHTTPリクエスト内にクッキーを含めることを許可する
CORS_ALLOW_CREDENTIALS = True
# アクセスを許可したいURL(アクセス元)を追加
CORS_ALLOWED_ORIGINS = "localhost:9000"
# プリフライト(事前リクエスト)の設定
# 30分だけ許可
CORS_PREFLIGHT_MAX_AGE = 60 * 30

以下のような画面が表示されたら成功です

スクリーンショット 2023-08-19 9.38.00.png

実際にAPI仕様書を作成してみよう!

ここから以下のAPIのドキュメントを作成していきます

  • ログイン
  • ユーザ
    • 一覧表示
    • 詳細

ログイン

doc/openapi.yml
# タグ
tags:
  - name: login
    description: ログインAPI
    externalDocs:
      description: ログインについて
      url: https://qiita.com/shun198/items/067e122bb291fed2c839

  # APIのパス
  /api/login/:
    post:
      tags:
        - login
      summary: ログインAPI
      description: アプリケーションにログインする
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                employee_number:
                  type: string
                  description: 社員番号
                  example: "00000001"
                password:
                  type: string
                  description: パスワード
                  example: "test"
              required:
                - "employee_number"
                - "password"
      responses:
        # 成功した時と失敗した時など複数以上のResponse例を記載できる
        "200":
          description: ログインに成功
          content:
            application/json:
              schema:
                type: object
              example:
                role: "MANAGEMENT"
        "400":
          description: ログインに失敗
          content:
            application/json:
              schema:
                type: object
              example:
                msg: "社員番号またはパスワードが間違っています"

/api/login/に以下に表示させたい項目を記載していきます
RequestとResponseのschemaの下に必要な項目の詳細や入力する値のデフォルト値などを設定できます

スクリーンショット 2023-08-19 19.25.52.png

こちらはSchemaを選択すると表示されます
スクリーンショット 2023-08-19 19.26.19.png

また、タグをつけることでSwagger内にAPIの仕様の詳細のリンクを貼ったりできます
スクリーンショット 2023-08-19 19.26.52.png

以下のように作成されたら成功です
スクリーンショット 2023-08-19 19.19.50.png
スクリーンショット 2023-08-19 19.20.15.png

認証の設定

ログイン機能を実装した際は認証の設定をSwagger側でする必要があります
今回はBasic認証の設定方法を記載します

doc/openapi.yml
openapi: 3.1.0
info:
  title: project
  description: |-
  version: 1.0.0
servers:
  - url: http://localhost:8000/

# basic認証の設定
components:
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic

security:
  - basicAuth: [] 

securityに認証方法を記載することで一度認証に成功すれば、認証が必要なAPI全てにアクセスできるようになります

以下のような認証画面が表示されたら成功です
スクリーンショット 2023-08-19 19.32.43.png

スクリーンショット 2023-08-19 19.33.20.png

ユーザのAPI

ここからユーザAPIの

  • 一覧表示
  • 詳細

の設定方法について解説していきます

一覧表示

doc/openapi.yml
  /api/users/:
    get:
      tags:
        - users
      summary: システムユーザのAPI
      description: システムユーザを一覧表示する
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
              properties:
                id:
                  type: string
                  description: UUID
                employee_number:
                  type: string
                  description: 社員番号
                username:
                  type: string
                  description: ユーザ名
                email:
                  type: string
                  description: メールアドレス
                role:
                  type: int
                  description: ロール
              examples:
                user_example:
                  value:
                    - id: "00000000-0000-0000-0000-000000000001"
                      employee_number: "00000001"
                      username: "test01"
                      email: "test01@example.com"
                      role: 0
                    - id: "00000000-0000-0000-0000-000000000002"
                      employee_number: "00000002"
                      username: "test02"
                      email: "test02@example.com"
                      role: 1
                    - id: "00000000-0000-0000-0000-000000000003"
                      employee_number: "00000003"
                      username: "test03"
                      email: "test03@example.com"
                      role: 2
                    - id: "00000000-0000-0000-0000-000000000004"
                      employee_number: "00000004"
                      username: "test04"
                      email: "test04@example.com"
                      role: 0

一覧表示など複数以上のJSONデータを表示させるときは以下のようにexamplesの下に値を記載していきます
以下のように表示されたら成功です

スクリーンショット 2023-08-19 19.37.48.png
スクリーンショット 2023-08-19 19.38.09.png

詳細

今回は/api/users/{id}/を例に記載します
IDをなどのパラメータを指定するときはparametersに記載することでデフォルト値をあらかじめ入れることができます

doc/openapi.yml
  # APIのパス内にIDがあるときは以下のように{id}と記載
  /api/users/{id}/:
    get:
      tags:
        - users
      summary: システムユーザのAPI
      description: 該当するUUIDのシステムユーザを取得する
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
              example:
                id: "00000000-0000-0000-0000-000000000001"
                employee_number: "00000001"
                username: "test01"
                email: "test01@example.com"
                role: 0
      parameters:
        - name: id
          in: path
          required: true
          description: 取得したいシステムユーザのUUID
          schema:
            type: string
          example: "00000000-0000-0000-0000-000000000001"

以下のように表示されたら成功です
スクリーンショット 2023-08-19 19.43.21.png

完成

ユーザのAPIのCRUD操作もまとめると以下のようになります

doc/openapi.yml
# https://swagger.io/specification/
openapi: 3.1.0
info:
  title: project
  description: |-
  version: 1.0.0
servers:
  - url: http://localhost:8000/

# basic認証の設定
components:
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic

security:
  - basicAuth: [] 

tags:
  - name: login
    description: ログインAPI
    externalDocs:
      description: ログインについて
      url: https://qiita.com/shun198/items/067e122bb291fed2c839
  - name: users
    description: システムユーザ関連のAPI

paths:
  /api/login/:
    post:
      tags:
        - login
      summary: ログインAPI
      description: アプリケーションにログインする
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                employee_number:
                  type: string
                  description: 社員番号
                  example: "00000001"
                password:
                  type: string
                  description: パスワード
                  example: "test"
              required:
                - "employee_number"
                - "password"
      responses:
        "200":
          description: ログインに成功
          content:
            application/json:
              schema:
                type: object
              example:
                role: "MANAGEMENT"
        "400":
          description: ログインに失敗
          content:
            application/json:
              schema:
                type: object
              example:
                msg: "社員番号またはパスワードが間違っています"
          
  /api/users/:
    get:
      tags:
        - users
      summary: システムユーザのAPI
      description: システムユーザを一覧表示する
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
              properties:
                id:
                  type: string
                  description: UUID
                employee_number:
                  type: string
                  description: 社員番号
                username:
                  type: string
                  description: ユーザ名
                email:
                  type: string
                  description: メールアドレス
                role:
                  type: int
                  description: ロール
              examples:
                user_example:
                  value:
                    - id: "00000000-0000-0000-0000-000000000001"
                      employee_number: "00000001"
                      username: "test01"
                      email: "test01@example.com"
                      role: 0
                    - id: "00000000-0000-0000-0000-000000000002"
                      employee_number: "00000002"
                      username: "test02"
                      email: "test02@example.com"
                      role: 1
                    - id: "00000000-0000-0000-0000-000000000003"
                      employee_number: "00000003"
                      username: "test03"
                      email: "test03@example.com"
                      role: 2
                    - id: "00000000-0000-0000-0000-000000000004"
                      employee_number: "00000004"
                      username: "test04"
                      email: "test04@example.com"
                      role: 0
    post:
      tags:
        - users
      summary: システムユーザのAPI
      description: システムユーザを登録する
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                employee_number:
                  type: string
                  description: 社員番号
                  example: "00000005"
                username:
                  type: string
                  description: ユーザ名
                  example: "test05"
                email:
                  type: string
                  description: メールアドレス
                  example: "test05@example.com"
                role:
                  type: int
                  description: ユーザ名
                  example: 0
              required:
                - "employee_number"
                - "username"
                - "email"
                - "role"
      responses:
        '201':
          description: 成功
          content:
            application/json:
              schema:
                type: object
              example:
                id: "Random UUID"
                employee_number: "00000005"
                username: "test05"
                email: "test05@example.com"
                role: 0

  /api/users/{id}/:
    get:
      tags:
        - users
      summary: システムユーザのAPI
      description: 該当するUUIDのシステムユーザを取得する
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
              example:
                id: "00000000-0000-0000-0000-000000000001"
                employee_number: "00000001"
                username: "test01"
                email: "test01@example.com"
                role: 0
      parameters:
        - name: id
          in: path
          required: true
          description: 取得したいシステムユーザのUUID
          schema:
            type: string
          example: "00000000-0000-0000-0000-000000000001"

    put:
      tags:
        - users
      summary: システムユーザのAPI
      description: 該当するUUIDのシステムユーザを更新する
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                employee_number:
                  type: string
                  description: 社員番号
                  example: "00000005"
                username:
                  type: string
                  description: ユーザ名
                  example: "test05"
                email:
                  type: string
                  description: メールアドレス
                  example: "test05@example.com"
                role:
                  type: int
                  description: ユーザ名
                  example: 0
              required:
                - "employee_number"
                - "username"
                - "email"
                - "role"
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
              example:
                id: "00000000-0000-0000-0000-000000000004"
                employee_number: "00000004"
                username: "test04"
                email: "test04@example.com"
                role: 0
      parameters:
        - name: id
          in: path
          required: true
          description: 更新したいシステムユーザのUUID
          schema:
            type: string
          example: "00000000-0000-0000-0000-000000000004"

    patch:
      tags:
        - users
      summary: システムユーザのAPI
      description: 該当するUUIDのシステムユーザを一部更新する
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                employee_number:
                  type: string
                  description: 社員番号
                  example: "00000005"
                username:
                  type: string
                  description: ユーザ名
                  example: "test05"
                email:
                  type: string
                  description: メールアドレス
                  example: "test05@example.com"
                role:
                  type: int
                  description: ユーザ名
                  example: 0
              required:
                - "employee_number"
                - "password"
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
              example:
                id: "00000000-0000-0000-0000-000000000004"
                employee_number: "00000004"
                username: "test04"
                email: "test04@example.com"
                role: 0
      parameters:
        - name: id
          in: path
          required: true
          description: 一部更新したいシステムユーザのUUID
          schema:
            type: string
          example: "00000000-0000-0000-0000-000000000004"

    delete:
      tags:
        - users
      summary: システムユーザのAPI
      description: 該当するUUIDのシステムユーザを削除する
      responses:
        '204':
          description: 成功
          content:
            application/json:
              schema:
                type: object
      parameters:
        - name: id
          in: path
          required: true
          description: 削除したいシステムユーザのUUID
          schema:
            type: string
          example: "00000000-0000-0000-0000-000000000004"

まとめ

ドキュメント作成に必要な項目を一通り記載してみました

  • Dockerでローカルを汚さない
  • GitHubでAPI仕様書をバージョン管理できる
  • SwaggerでAPIの検証ができる

ことに大きな魅力を感じますね
今後は

  • ファイルのアップロード
  • クエリパラメータ

などの設定方法も追記していきたいと思います

参考

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?