みなさん、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ボタンに虫眼鏡のマークが書かれているボタンを押します。
neovim
neovimでは、swagger-preview.nvimというプラグインを入れます。
READMEを見ながら、各種の設定に合わせて使ってみてください。
一応自分はAstroNvimを使っていて、下のように設定しました。
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
を必ず押してください
その他(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: path
をquery
に変えるだけです.
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オブジェクトの配列を定義 |
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名'
実際に仕様書を書いてみる
今回は、ユーザー管理のアプリケーションを例にしてやってみようと思います。
実際に書いた仕様書は下のようになります。
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
大体このような感じで書けばいいので、ぜひ共同開発等で書いてみてください