はじめに
複数のサブシステムから構成されるサービスで、各システムを連携するためAPIを作成、運用する機会がありました。
保守性の高いシステムとするため、REST API と RFC 9110 (HTTP Semantics)に基づき、標準規格に従った設計と実装を行いました。
ここではLaravelでAPIを実際に作成し、標準規格に則った設計と実装を紹介します。
REST API と RFCの役割
REST API
Representational State Transferの略。GET、POSTなどのHTTPプロトコルを用いてデータなどのリソースを操作するAPI設計原則
RFC
インターネット技術の標準化団体 IETF が発行する、インターネット技術の仕様や運用ルールを定めた公式文書
HTTPステータスコードやメソッド(GET、POSTなど)の挙動は RFC 9110 などで定義されている
主なRFC
- RFC 791: インターネットプロトコル (IP)
- RFC 793: 伝送制御プロトコル (TCP)
- RFC 2616 (後継あり): HTTP/1.1
- RFC 5321/5322: メール送信 (SMTP) とメッセージ形式
LaravelでAPIを作成する
Laravelのプロジェクトを作成する
$ composer create-project --prefer-dist laravel/laravel .
Creating a "laravel/laravel" project at "./"
Installing laravel/laravel (v12.11.2)
...
Sailをインストール
$ composer require laravel/sail --dev
./composer.json has been updated
Running composer update laravel/sail
...
No security vulnerability advisories found.
Using version ^1.53 for laravel/sail
$ php artisan sail:install
┌ Which services would you like to install? ───────────────────┐
│ mysql │
└──────────────────────────────────────────────────────────────┘
INFO Sail scaffolding installed successfully. You may run your Docker containers using Sail's "up" command.
➜ ./vendor/bin/sail up
WARN A database service was installed. Run "artisan migrate" to prepare your database:
➜ ./vendor/bin/sail artisan migrate
Sailでコンテナを起動
./vendor/bin/sail up -d
...
[+] Running 5/5
✔ laravel.test Built 0.0s
✔ Network laravel-qiita-app_sail Created 0.0s
✔ Volume "laravel-qiita-app_sail-mysql" Created 0.0s
✔ Container laravel-qiita-app-mysql-1 Started 0.6s
✔ Container laravel-qiita-app-laravel.test-1 Started
※エイリアスをつけておく
alias sail='[ -f sail ] && bash sail || bash vendor/bin/sail'
マイグレートしテーブルを作成
$ sail artisan migrate
INFO Preparing database.
Creating migration table ............................................................................................................ 10.57ms DONE
INFO Running migrations.
0001_01_01_000000_create_users_table ................................................................................................ 29.06ms DONE
0001_01_01_000001_create_cache_table ................................................................................................ 17.76ms DONE
0001_01_01_000002_create_jobs_table ................................................................................................. 27.51ms DONE
API機能をインストール
$ sail artisan install:api
bootstrap/app.php にAPIのルーティングが追加されているか確認する
<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware): void {
//
})
->withExceptions(function (Exceptions $exceptions): void {
//
})->create();
API用のコントローラを作成する
sail artisan make:controller UserController --api
INFO Controller [app/Http/Controllers/UserController.php] created successfully.
--api フラグにより、create や editを除いた、データ操作用のメソッド(index, store, show, update, destroy)が生成されます
ルーティングを設定
use App\Http\Controllers\UserController;
use Illuminate\Support\Facades\Route;
Route::apiResource('users', UserController::class);
これにより、以下のようなREST APIの原則に従ったマッピングとなります
| メソッド | パス | 役割 | RFC 9110の定義 |
|---|---|---|---|
| GET | /users | 一覧取得 | 取得。べき等かつ安全。 |
| POST | /users | 新規作成 | リソースの追加。べき等ではない。 |
| GET | /users{id} | 個別取得 | 指定リソースの取得 |
| PUT/PATCH | /users{id} | 更新 | 置換(PUT)または部分更新(PATCH) |
| DELETE | /users{id} | 削除 | リソースの削除。べき等。 |
TIPS
データが存在しないとき、200と404のどちらを返すべきか?
| ステータス | 意味 | 判断基準 |
|---|---|---|
| 200 | リクエストは成功(空を返す) | 例:検索条件に合うものが0件の場合 |
| 404 | リソース自体が存在しない | 例:ユーザー取得API(/users/123)でそのIDが存在しない場合 |
まとめ
REST API と RFC 9110 (HTTP Semantics)という標準規格に従うことで以下のメリットがあります。
- 独自ルールではなく共通ルールに従うことでコミュニケーションコストを削減できる
- 言語、フレームワーク、ブラウザ、サーバ...などはRFCに基づいて動作しているため、APIもRFCに従うことで不必要な事故を回避できる
- APIを利用する側にとって期待している動作をしてくれるため扱いやすくなる
REST APIやRFCを把握し理解していくのは大変骨の折れる作業ですが...
APIの品質を高めるためにも一度ドキュメントに目を通してみると新たな発見があるかもしれません。