LaravelとScribeで効率的にAPI仕様書を生成する
管理機能はLaravelで、フロントエンドはスマホアプリやWebブラウザの組み合わせで、という構成が増えてきました。
こういった構成ではサーバー側とフロント側の開発者が異なり、API仕様を共有する必要がある場面が多いと思います。
その際、手で仕様書を作ることも可能ですが、API開発中に項目が変わったり、出力形式を変えたくなった場合、かなり手間ですし、更新漏れがあるので現実的ではないと思います。
そういった問題を解決するため、API仕様書を機械的に生成するknuckleswtf/scribeというライブラリがあります。
しかし、API仕様書の生成を機械的に行えるといっても、生成元の定義は何かしらの方法でLaravel内に記述する必要があります。
そこで今回は私なりに考えた、できるだけ実際のプログラムの変更に追従したAPI仕様書の生成を行うための構成をご紹介します。
Laravelでのベストプラクティスかわかりませんが、APIを開発する際の参考になればと思います。
また、サンプルリポジトリも公開していますので、合わせて確認いただければと思います。
インストール
基本となるLaravelのプロジェクトは準備できている前提です。
次のコマンドでknuckleswtf/scribeをインストールし、設定ファイルなどを生成します。
composer require --dev knuckleswtf/scribe
php artisan vendor:publish --provider="Knuckles\Scribe\ScribeServiceProvider" --tag=scribe-config
次に、生成された設定ファイルの内容を変更します。
config/scribe.phpの「type」を「laravel」に変更
サンプル用のモデルやテーブルの準備
今回は店舗一覧情報を取得するAPIを開発する想定でモデルやマイグレーションファイルを作成します。
具体的には店舗情報として「Shop」、メニュー情報として「Menu」モデルを作成します。
実際のファイルはサンプルリポジトリをご確認ください。
店舗とメニュー情報のファクトリーを準備
ファクトリーは主にテストデータ生成などのために作ると思いますが、ファクトリーを作っておくとScribeで仕様書を作成した際の出力例に適用されるため、店舗とメニュー情報のファクトリーを作成しておきます。
実際のファイルはサンプルリポジトリをご確認ください。
店舗一覧出力用のリソースを準備
APIで出力する店舗一覧データ整形用にリソースファイルを作成します。
実際のファイルはサンプルリポジトリをご確認ください。
店舗一覧APIのエンドポイント用コントローラーなどを準備
ルートの設定、コントローラーの作成を行います。
コントローラーにはアノテーションでScribe用の設定を記述しています。
サンプルリポジトリではこの箇所です。
それぞれ次のような意味があります。
最初の「店舗一覧取得」はAPI名です。
次の「同時にメニュー情報も付属します。」はAPIの説明文です。
「@unauthenticated」はログイン不要でアクセスできることを示します。実際にログイン不要かどうかはここでは制御していません。あくまでScribeの記述のみです。
「@group Shop」はAPIのカテゴリです。自由に記述できます。
「@apiResourceCollection App\Http\Resources\Api\ShopResource」はリストで返す場合に適用するリソースの指定です。
「@apiResourceModel App\Models\Shop with=menus」はAPIから返す各要素のモデルの指定です。
「with=menus」をつけることで、サンプルレスポンスにメニュー情報のリストが追加されます。
仕様書を生成する
ここまでで最低限の準備が終わったため、一度API仕様書を生成します。
次のコマンドを実行します。
php artisan scribe:generate
ブラウザで「http://localhost/docs」にアクセスします(ホスト名の部分は実行環境により異なる可能性があります)。
↓のようなページが表示されるかと思います。
Scribeはデフォルトで/api以下のルートを仕様書に含めてくれるため、先ほど作ったShopControllerのindexが記載されています。
また、ファクトリーを用意しておいたので、「Example response (200):」の下に次のようにサンプルデータが表示されていると思います。
出力する項目を変更する
テーブル上の全項目をそのままAPIで出力して良ければ以上で完了ですが、実際には出力したくない項目や、形式を変えて出力したいなどの要件があると思います。
そういった際は基本的にリソースファイルを変更します。
例として次のような変更を行います。
- メニューの「cost」項目は除外する
- 作成日や更新日は除外する
まずメニュー用のリソースを作成します。 実際のファイルはサンプルリポジトリをご確認ください。
次に店舗用のリソースのtoArrayメソッドを変更します。 実際のファイルはサンプルリポジトリをご確認ください。
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'introduction' => $this->introduction,
'menus' => MenuResource::collection($this->menus),
];
}
仕様書を更新します。
php artisan scribe:generate
仕様書を確認すると、↓のように期待通りのサンプルデータが表示されていると思います。
実際のAPIの実行結果を確認する
Scribeが生成した画面から実際のAPIにリクエストを行い、結果を閲覧することも可能です。
テーブルとデータを用意する
まだマイグレーションを実行していない場合はマイグレーションを実行します。
テストデータを入れる
サンプルリポジトリにはテストデータ生成用のSeederも含まれているので、次のコマンドでテストデータを生成します。
php artisan db:seed --class=ShopSeeder
Scribeの仕様書からAPIを実行する
「店舗一覧取得」の少し下にある「Try it out」ボタンを押してから表示される「Send Request」を押します。
すると次のように「Received response (200):」の下に実際の実行結果が表示されます。
API仕様書と同じ形式で実際のレスポンスが返ってきていることが確認できました。
これ以降は主にリソースファイルを変更し、Scribeを再生成するだけで最新の仕様書が手に入る状態になります。
まとめ
knuckleswtf/scribeを活用した、実装からAPI仕様書を生成する手順や構成についてご紹介しました。
Scribeの再生成が面倒ではありますが、API仕様書の作成工数がほぼなくなり、ミスも少ない構成になったと思います。
また、こういったAPI仕様書はSwagger UIを使うことも多いと思いますが、ScribeはOpenAPI形式での出力も行ってくれるため、それをそのままSwagger UIに渡すことも可能です。