3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

swaggerでAPIの仕様書を書こう!

Last updated at Posted at 2024-11-04

みなさん、swaggerを使ったことがありますか?

私自身、最近swaggerを使うようになってきたので、今回はswaggerについてまとめてみようと思います。

swaggerとは

OpenAPI Specification(OAS)と呼ばれる、RestfulAPIを構築するためのオープンソースのフレームワークのことです。

昔は、wordやexcelでAPIの仕様書が書かれていましたが、近年ではswaggerが一般化してきたそうです。

OpenAPIとは

APIの仕様を記述するためのフレームワークやツールです。

OpenAPIは、ソフトウェアアプリケーション同士がやり取りするAPIの仕様書のフォーマットを標準化して、簡単に作成するために作られました。

RestfulAPIとは

RestfulAPIとは、RESTと呼ばれる考え方に沿ったAPIのことを指します。

RESTAPIという言い方もありますが、RestfulAPIとRESTAPIは同じものと考えても大丈夫そうです。

RESTとは

Representational State Transpherの略で、分散システムにおいて複数のソフトウェアが連携しやすくするための設計思想(アーキテクチャスタイル)のことを指します。

このRESTには色々原則があるのですが、今回は6原則だけピックアップしていこうと思います。

クライアント/サーバー

RESTでは、クライアント/サーバーという形式をとっています。
クライアントがリクエストを送ることで、それに対してサーバーが処理をしてクライアントにレスポンスを返すという形式です。

ステートレスサーバー

ステートレスとは、状態を保持しないことを指します。

つまり、ステートレスサーバーとはサーバーはクライアントアプリケーションの状態を保持しないことです。

ただ例外として、最小限のCookieを使用してステートフルなサーバーとして扱うこともあります。

キャッシュ

キャッシュとは、一度クライアントがサーバから取得したリソースを使い回す方式です。

統一インターフェース

URIで指定したリソース操作を統一した限定的なインターフェースで行うことです。

この説明だけだと分かりにくいですが、APIを定義するときにHTTPメソッドは何でJSONの構造はどうするかということを決めると思います。
これを決めることで特定の機能を持ったAPIの叩く方式を一つにすることができ、これを統一インターフェースと言います。

階層化システム

階層化システムとは、webサーバーより前にロードバランサーを置いて負荷分散を行ったり、プロキシをおいてファイアーウォールの役割を行ったり、クライアントからみてサーバーに到達するまでに色々な階層を渡っていくような構造になっていることを指します。

コードオンデマンド

プログラムコードをサーバーから取得して、クライアントで動かす形式のことです。
つまり、動的にクライアントアプリケーションのコードを生成して、柔軟に動作させることができます。

swaggerを使うメリット

メリットとしては、先ほど紹介したRESTの統一インターフェースを共通認識にできるのが大きいです。

アプリケーションにおいて、APIの仕様を共有するのはとても難しいです。
特に見た目の面でURIがどれでリクエストボディがどれでレスポンスボディがどれでというのを共通認識として共有するのは至難の技です。

APIの仕様を書く場所や書き方をサーバーサイド側でしっかり共通認識を持っていないと、APIがバラバラのとこで定義され、フロント側がサーバーサイドのコードを読まなければならないという、フロント側がサーバーとの通信の実装でとても苦労することになります。

swaggerを使うことでOpenAPIのAPI定義仕様を楽に定義、そして分かりやすく共有することができるので、開発効率を上げることができます。

swaggerを使ってみる

執筆環境を整える

swaggerは、vscodeや各種IDEの拡張機能で簡単にプレビューすることが可能です。

VSCode

vscodeでは下のOpenAPI(SwaggerEditor)を使用します。

VSCode上の右上のSplitボタンに虫眼鏡のマークが書かれているボタンを押します。
スクリーンショット 2024-10-04 13.55.49.png

そうすることでプレビューすることができます。
スクリーンショット 2024-10-04 13.57.14.png

neovim

neovimでは、swagger-preview.nvimというプラグインを入れます。

READMEを見ながら、各種の設定に合わせて使ってみてください。

一応自分はAstroNvimを使っていて、下のように設定しました。

swagger-preview.lua
return {
  "vinnymeller/swagger-preview.nvim",
  config = function()
    require("swagger-preview").setup {
      -- The port to run the preview server on
      port = 8000,
      -- The host to run the preview server on
      host = "localhost",
    }
  end,
}

Jetbrains系のIDE

openapi-swagger-editorというプラグインを入れます。

settingsから下の画像のような場所からインストールすることができます。インストールしたらApplyを必ず押してください

スクリーンショット 2024-11-04 3.27.33.png

その他(SwaggerEditor)

また、エディタの拡張機能以外にも、SwaggerEditorというオンラインエディタでは、環境が手元になくてもプレビューができるので特におすすめです。

swaggerのファイルを作成する

swaggerのファイル拡張子は、.swagger.ymlとなります。

例えば、todoアプリのswaggerファイルを作るとなったら

todo.swagger.yml

となります。

swaggerの書き方を学ぶ

OpenAPIのversion

まず、使用するOpenAPIのversionを記述します。

openapi: 3.0.0

Info

Infoでは、タイトルや説明などのAPI全体における情報を記述します。

info:
    title: [titleを記述]
    description: [説明を記述]
    version: [versionを記述

tags

tagsでは、URIをカテゴリとして分けることができます。

タグは下のように宣言します。

tags:
  - name: [タグの名前を記述]
    description: [タグの説明を記述]

paths

pathsでは、エンドポイントの指定やHTTPのメソッドはGETなのかPOSTなのかを記述します。

paths:
  /:
    get:
      summary: 概要
      description: 説明
      tags:
        - タグ名

上の場合だとエンドポイントは/となり、HTTPのメソッドはGETリクエストでの場合を指定しています。

summaryでは、概要を記述することができます。

descriptionでは、説明を記述することができます。

また、tagsで先ほど作成したタグをアタッチして、カテゴライズすることができます。

HTTPのメソッドは以下の8つです。

メソッド 用途
GET リソースの取得
POST リソースの送信
HEAD ヘッダーの取得
PUT リソースの更新
DELETE リソースの削除を行います
CONNECT 双方向の通信を行う
OPTIONS 通信オプションを取得
TRACE ループバックテストを実行
PATCH リソースの1部分を変更

また、パスパラメータを使いたい場合は下のように書きます。

/tasks/{taskId}:
    get:
      operationId: todo-detail
      description: "todoタスクの詳細を表示します"
      tags:
        - todo
      parameters:
        - name: "taskId"
          in: path
          description: "詳細を取得したいtodoタスクのID"
          required: true
          type: "integer"
          format: "int64"
          example: 1

クエリパラメーターの場合はin: pathqueryに変えるだけです.

in: query

RequestBody

RequestBodyでは、クライアントが送るリクエストの構造体を定義します。

jsonを送る場合は下のように定義します。

requestBody:
  content:
    application/json:
      schema:
        type: object
        properties:
          プロパティ1:
            type: string
            format: string
            description: "プロパティ1の説明"
            example: "プロパティ1の例"
          プロパティ2:
            type: string
            format: string
            description: "プロパティ2の説明"
            example: "プロパティ2の例"
        required:
          - プロパティ1
          - プロパティ2

schemaの下にjsonの構造を書くことができます。

typeで以下のように設定できます。

type 説明
object Jsonオブジェクトを定義
array Jsonオブジェクトの配列を定義

type arrayの場合の書き方

type arrayの場合は下のようにitemsを追記します。

type: array
items:
  type: object
  properties:

propertiesの下にJsonの要素となるプロパティを設定することができ、下の表のようにフィールドを設定できます。

フィールド 記述内容
type string, number, integer, boolean, array, fileからタイプを選ぶ
format アプリで使用するフォーマットを指定する
description 説明を記述
example 実際に扱う際の具体値を設定

requiredで必要なプロパティを指定できます。

ResponseBody

ResponseBodyは返ってくる可能性のあるレスポンスを定義しています。

responses:
  '200':
    description: Successful response
    content:
      application/json:
        schema:

responsesの下にはステータスコードを設定できます。

descriptionでレスポンスに関する説明を書くことができます。

components

先ほど定義したJsonのスキーマですがコンポーネント化して使い回すことが可能です。

components:
  schemas:
    object名:
      type: object
      properties:
        プロパティ1:
          type: string
          format: string
          description: "プロパティ1の説明"
          example: "プロパティ1の例"
        プロパティ2:
          type: string
          format: string
          description: "プロパティ2の説明"
          example: "プロパティ2の例"
      required:
        - プロパティ1
        - プロパティ2

このJsonオブジェクトコンポーネントはRequestBody等で書いていた内容を以下に変更すれば、簡単に適応できます。

content:
  application/json:
    schema:
      $ref: '#/components/schemas/object名'

実際に仕様書を書いてみる

今回は、ユーザー管理のアプリケーションを例にしてやってみようと思います。

実際に書いた仕様書は下のようになります。

example.swagger.yml
openapi: 3.0.0
info:
  title: User Management API
  description: A simple API to manage user information
  version: 1.0.0

tags:
  - name: users
    description: User Management API

paths:
  /users:
    get:
      summary: List all users
      tags:
        - users
      responses:
        '200':
          description: Successful response
          content:
            application/json:    
              schema:
                type: object
                properties:
                  users:
                    type: array
                    items:
                      $ref: '#/components/schemas/User'
    post:
      summary: Create a new user
      tags:
        - users
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NewUser'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
  /users/{userId}:
    get:
      summary: Get a user by ID
      tags:
        - users
      parameters:
        - name: userId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
    put:
      summary: Update a user
      tags:
        - users
      parameters:
        - name: userId
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NewUser'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
    delete:
      summary: Delete a user
      tags:
        - users
      parameters:
        - name: userId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '204':
          description: Successful response

components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: integer
        username:
          type: string
        email:
          type: string
        createdAt:
          type: string
          format: date-time
    NewUser:
      type: object
      properties:
        username:
          type: string
        email:
          type: string
      required:
        - username
        - email

大体このような感じで書けばいいので、ぜひ共同開発等で書いてみてください

3
2
1

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
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?