📝

Swagger(OpenAPI)によるAPI設計

2024/03/05に公開

API設計の手順

API設計の手順を明確にすることで、どのような情報が必要か・定義すべきかを明確にし手戻りを防ぐ。
今回はSwagger(OpenAPI)によるAPI設計手法について実際のSwaggerに書くコードを示しながら0から解説していく。
(ChatGPTフル活用。)

API設計の粗さはシステムのバグやセキュリティの脆弱性に顕著に出る。
備忘録として残しているが、参考までに。

00.必要な資料の準備

  • ERD(データベース設計資料)
  • フローチャート
  • 画面仕様書
  • 機能設計書

01.リソース(データモデル)の洗い出し

例)ベーシックなECシステム

  • ユーザー(Users)
  • 商品(Products)
  • カテゴリー(Categories)
  • 注文(Order)
  • 支払い情報(Payments)

02.リソースの関係性を定義する

洗い出したリソース感の関係性(has_one has_many dependency)などを定義する。
ここでERDを作成しながらどのようなスキーマになるかを策定する。

ERD参考:
※準備中

03.スキーマの作成

Swaggerの中でスキーマを作成する。
例)userのスキーマ

swagger
components:
  schemas:
    User:
      type: object
      properties:
        userId:
          type: string
        name:
          type: string
        email:
          type: string
        password:
          type: password

04.APIエンドポイントの設計

画面設計書のアクション(ユーザーインタラクション)を基にエンドポイントを作成する。

エンドポイントの命名には以下を気をつける必要がある。

  • リソースは複数形を使用する("users" "orders")など
  • 直感的で分かりやすい名称を使用する
  • 単語の区切りはケバブケースを使用する(system-users)
  • 特殊記号は使用しない
  • ファイル拡張子はできるだけ使用しない
  • URL中のパラメータ・ID部分はキャメルケースを使用する({orderId})
  • レスポンスにリソースの総数を含める
    など。

参考:REST API設計について整理してみた

Swaggerへの落とし込み

エンドポイントを洗い出せたら(洗い出しながら)HTTPメソッド・パラメータと共にSwaggerへ落とし込んでいく。

Swagger
paths:
  /users/{userId}:
    get:
      summary: ユーザー情報を取得
      parameters:
        - name: userId
          in: path
          required: true
          description: ユーザーID
          schema:
            type: string

05.レスポンスとエラーハンドリングの設計

エンドポイントを全て洗い出せたら、レスポンスを記載していく。

Swagger
paths:
  /users/{id}:
    get:
      summary: ユーザー情報を取得
      parameters:
        - name: id
          in: path
          required: true
          description: ユーザーID
          schema:
            type: string
      responses:
        '200':
          description: ユーザーの詳細情報を返します
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
              examples: #examplesフィールドを活用した方が良い
                user:
                  summary: ユーザーの例
                  value:
                    id: "1"
                    name: "山田 太郎"
                    email: "taro@example.com"

エラーハンドリング

ステータスコード別にエラー時のメッセージを定義しつつ、エラーハンドリングをする。

Swagger
paths:
  /users/{id}:
    get:
      summary: ユーザー情報を取得
      parameters:
        - name: id
          in: path
          required: true
          description: ユーザーID
          schema:
            type: string
      responses:
        '200': #成功時
          description: ユーザーの詳細情報を返します。
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400': #不正なリクエスト
          description: 不正なリクエストです。例:パラメータの形式が不正です。
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                invalidRequest:
                  summary: 不正なリクエストの例
                  value:
                    code: 400
                    message: "不正なパラメータです。"
        '404': #not found
          description: 指定されたユーザーが見つかりません。
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                notFound:
                  summary: ユーザーが見つからない例
                  value:
                    code: 404
                    message: "指定されたユーザーが見つかりません。"
components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        email:
          type: string
    Error: #エラーレスポンス
      type: object
      properties:
        code:
          type: integer
        message:
          type: string

セキュリティと認証

APIセキュリティの必要性

利用するAPIが改善されていた場合、不正なデータが返ってくる場合や個人情報などのデータが傍受されてしまうリスクがある。

決済サービスや金融機関などのAPIを使用する際、認証情報が傍受されてしまうと金銭的被害が生まれる可能性も。

APIセキュリティの設計

設計段階でどのようなセキュリティ対策が必要か、どのようなセキュリティ技術を活用するか、どのように実装していくかを明確にする。

01.認証メカニズムの設計

認証方式の種類

  • APIキー:APIの利用者に固有のキーを発行し、それをAPIリクエストに含めることで認証を行う
  • ベアラートークン / JWT:トークンベースの認証方式。サーバーから発行されたトークンをリクエストヘッダーに含めることで認証を行う。
  • OAuth2.0:第三者アプリケーションがユーザーの代わりにリソースにアクセスするための認証フレームワーク。

上記いずれかまたは複数を採用しセキュリティを強化する。

02.権限付与

APIそれぞれのリソースに対するアクセス権限を定義しアクセス制限をかける。

例)

  • アクセス可能 / 不可
  • 読み取り専用
  • 読み書き可能

03.通信のセキュリティ

HTTPS(SSL化)を使用することでAPIとクライアント間の通信を保護できる。

04.脆弱性対策

SQLインジェクション・クロスサイトスクリプティング(XSS)などの脆弱性への対応・対策。
例)エスケープ処理など

Swaggerでの設計

Swaggerでは **"securitySchemes"**を用いることでAPIのセキュリティスキームを定義できる。

コード例(API key)

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

コード例(OAuth2.0)

Swagger
components:
  securitySchemes:
    OAuth2:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: https://example.com/oauth/authorize
          tokenUrl: https://example.com/oauth/token
          scopes:
            read: 読み取りアクセス権
            write: 書き込みアクセス権
security:
  - OAuth2:
      - read
      - write

Usesリソースに対する最終的なSwaggerの記載

Swagger
openapi: 3.0.0
info:
  title: Users API
  version: 1.0.0
servers:
  - url: https://example.com/api
paths:
  /users:
    get:
      summary: ユーザーの一覧を取得
      responses:
        '200':
          description: 成功
        '400':
          description: 不正なリクエスト
      security:
        - ApiKeyAuth: []
    post:
      summary: 新しいユーザーを作成
      responses:
        '200':
          description: ユーザー作成成功
        '400':
          description: 不正なリクエスト
      security:
        - ApiKeyAuth: []
  /users/{userId}:
    get:
      summary: 特定のユーザーの詳細情報を取得
      parameters:
        - name: userId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: 成功
        '404':
          description: ユーザーが見つからない
      security:
        - ApiKeyAuth: []
    put:
      summary: 特定のユーザー情報を更新
      parameters:
        - name: userId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: 更新成功
        '400':
          description: 不正なリクエスト
        '404':
          description: ユーザーが見つからない
      security:
        - ApiKeyAuth: []
    delete:
      summary: 特定のユーザーを削除
      parameters:
        - name: userId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: 削除成功
        '404':
          description: ユーザーが見つからない
      security:
        - ApiKeyAuth: []
components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        email:
          type: string
    Error:
      type: object
      properties:
        code:
          type: integer
        message:
          type: string
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-KEY

Discussion