Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Laravel で API バージョニングを実装するなら
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Shohei Okada
September 26, 2018
Programming
61
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Laravel で API バージョニングを実装するなら
2018-09-26 開催の「第130回 PHP勉強会@東京」におけるLT資料です
https://phpstudy.doorkeeper.jp/events/79982
Shohei Okada
September 26, 2018
More Decks by Shohei Okada
See All by Shohei Okada
Symfony + NelmioApiDocBundle を使った スキーマ駆動開発 / Schema Driven Development with NelmioApiDocBundle
okashoi
0
300
たった 1 枚の PHP ファイルで実装する MCP サーバ / MCP Server with Vanilla PHP
okashoi
1
930
どうして手を動かすよりもチーム内のコードレビューを優先するべきなのか
okashoi
3
2.3k
パスワードのハッシュ、ソルトってなに? - What is hash and salt for password?
okashoi
3
400
設計の考え方 - インターフェースと腐敗防止層編 #phpconfuk / Interface and Anti Corruption Layer
okashoi
11
6.1k
"config" ってなんだ? / What is "config"?
okashoi
0
1.8k
ファイル先頭の use の意味、説明できますか? 〜PHP の namespace と autoloading の関係を正しく理解しよう〜 / namespace and autoloading in php
okashoi
4
2.2k
MySQL のインデックスの種類をおさらいしよう! / overviewing indexes in MySQL
okashoi
0
1.4k
PHP における静的解析(あるいはそもそも静的解析とは) / #phpcondo_yasai static analysis for PHP
okashoi
1
1.5k
Other Decks in Programming
See All in Programming
軽量Java基盤の設計 DIコンテナに頼らない、長期保守と1秒起動の実現 JJUG CCC 2026 Spring
macha64
0
470
jQueryをバージョンアップする前に使いたいjQuery Migrate
matsuo_atsushi
0
200
Spec Driven Development | AI Summit Lisbon
danielsogl
PRO
0
170
メソッドのジェネリクスでGoの夢は広がるか? / Kyoto.go #65
utgwkk
3
620
柔軟なPDFレイアウトエディタを支える型システム設計 — Discriminated UnionとConditional Typeの実践
minako__ph
4
1.6k
PHPで使える日時の表現と、その知り方 #frontend_phpcon_do
o0h
PRO
0
210
さぁV100、メモリをお食べ・・・
nilpe
0
130
AIエージェントと協働するCLI開発 — BunとOpenClawで学んだこと
yoshikouki
1
240
コンテキストの使い捨てをやめる — ビジネスルール駆動開発と miko —
ioki
0
170
タクシーアプリ『GO』の バックエンド開発のおける AI利活用と若者のすべて
pyama86
3
1.9k
技術記事、AIに書かせるか、自分で書くか? 〜それでも私が自分の手で書く理由〜 / #QiitaConference
jnchito
2
1.3k
These Five Tricks Can Make Your Apps Greener, Cheaper, & Nicer
hollycummins
0
280
Featured
See All Featured
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
140
Crafting Experiences
bethany
1
170
Tell your own story through comics
letsgokoyo
1
950
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.4k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
180
The Art of Programming - Codeland 2020
erikaheidi
57
14k
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
0
140
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2k
Keith and Marios Guide to Fast Websites
keithpitt
413
23k
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
230
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
Music & Morning Musume
bryan
47
7.2k
Transcript
API バージョニング を Laravel で実装するなら 第130回 PHP勉強会@東京
岡田 正平(おかだ しょうへい)@okashoi • 株式会社ウィルゲート 2015年新卒入社 • 開発室 ソリューションユニット 所属
• PHP, Laravel, Vue.js 2 自己紹介 Slides:
クライアントに対し、古い形式でのアクセス方法を提供しつづける 例)Google Maps Embed API https://www.google.com/maps/embed/v1/place?q=...&key=... 新しいアクセス方法・レスポンス形式などは v2, v3… としていく
※他にもメディアタイプでバージョンを指定する方法などがある 3 API バージョニング
クライアントに対し、古い形式でのアクセス方法を提供しつづける 例)Google Maps Embed API https://www.google.com/maps/embed/v1/place?q=...&key=... 新しいアクセス方法・レスポンス形式などは v2, v3… としていく
※他にもメディアタイプでバージョンを指定する方法などがある 4 API バージョニング このスライドではいったん この方法で考えます
愚直に考えるとこう routes/api.php 5 Laravel でどう実装する?① Route::get('v1/posts', 'V1/PostController@index'); Route::get('v2/posts', 'V2/PostController@index');
愚直に考えるとこう routes/api.php 6 Laravel でどう実装する?① Route::get('v1/posts', 'V1/PostController@index'); Route::get('v2/posts', 'V2/PostController@index'); バージョンごとに
異なる Controller 明示的に指定
たしかに実現できてるけど…… • 新しいバージョンが増えるたびに、全てを追記するの? ➢ バージョンを扱う部分は仕組み化したい • コントローラを分割してしまうとコピペが横行するおそれアリ ➢ コントローラ内の条件分岐にしたい 7
Laravel でどう実装する?①
8 Laravel でどう実装する?① 参考)http://kenn.hatenablog.com/entry/2014/03/06/105249
改善案:ルーティングパラメータとして渡す 9 Laravel でどう実装する?② Route::get('{version}/posts', 'PostController@index') ->where('version', 'v[1-9][0-9]*'); routes/api.php public
function index(string $versionString, Request $request) { // 'v1' => 1 のように int 値に変換 $version = (int)substr($versionString, 1); if ($version === 1) { // v1 の処理 } // ... 以下略 } apps/MyApp/Application/Http/Controllers/PostConroller.php
改善案:ルーティングパラメータとして渡す 10 Laravel でどう実装する?② Route::get('{version}/posts', 'PostController@index') ->where('version', 'v[1-9][0-9]*'); routes/api.php public
function index(string $versionString, Request $request) { // 'v1' => 1 のように int 値に変換 $version = (int)substr($versionString, 1); if ($version === 1) { // v1 の処理 } // ... 以下略 } apps/MyApp/Application/Http/Controllers/PostConroller.php
改善案:ルーティングパラメータとして渡す 11 Laravel でどう実装する?② Route::get('{version}/posts', 'PostController@index') ->where('version', 'v[1-9][0-9]*'); routes/api.php public
function index(string $versionString, Request $request) { // 'v1' => 1 のように int 値に変換 $version = (int)substr($versionString, 1); if ($version === 1) { // v1 の処理 } // ... 以下略 } apps/MyApp/Application/Http/Controllers/PostConroller.php パターン指定による制限
改善案:ルーティングパラメータとして渡す 12 Laravel でどう実装する?② Route::get('{version}/posts', 'PostController@index') ->where('version', 'v[1-9][0-9]*'); routes/api.php public
function index(string $versionString, Request $request) { // 'v1' => 1 のように int 値に変換 $version = (int)substr($versionString, 1); if ($version === 1) { // v1 の処理 } // ... 以下略 } apps/MyApp/Application/Http/Controllers/PostConroller.php
①の問題点は解決できたものの、欲を言うなら • 毎 action で ←これやるの? ➢ 勝手に変換されていて欲しい • による制限が
に対してできない ➢ パターン指定は一箇所だけにしたい 13 Laravel でどう実装する?② $version = (int)substr($versionString, 1); ->where() Route::group() // できそうでできない Route::group(['prefix' => '{version}'], function () { Route::get('posts', 'PostController@index'); Route::get('users', 'UserController@index'); })->where('version', 'v[1-9][0-9]*');
None
アイディア:Explicit Route Model Binding を使う 15 Laravel でどう実装する?③ カスタマイズロジックを用いれば Eloquent
ORM 以外も Bind できる
1. API バージョンを表現するクラス (Value Object)を作る 2. RouteServiceProvider で Binding を(ついでに
pattern も)登録 3. Controller で利用する 16 Laravel でどう実装する?③
1. API バージョンを表現するクラス (Value Object)を作る 2. RouteServiceProvider で Binding を(ついでに
pattern も)登録 3. Controller で利用する 17 Laravel でどう実装する?③ class ApiVersion { /** * @var int */ protected $value; /** * @param string $versionString */ public function __construct(string $versionString) { $this->value = (int)substr($versionString, 1); } /** * @return int */ public function value(): int { return $this->value; } /** * @param int $number * @return bool */ public function is(int $number): bool { return $this->value === $number; } }
1. API バージョンを表現するクラス (Value Object)を作る 2. RouteServiceProvider で Binding を(ついでに
pattern も)登録 3. Controller で利用する 18 Laravel でどう実装する?③ public function boot(): void { Route::pattern('version', 'v[1-9][0-9]*'); parent::boot(); Route::bind('version', function ($versionString, $route) { return new ApiVersionValue($versionString); }); } tips: は より前 は より後 でないと正しく動かない Route::pattern() parent::boot() Route::bind() parent::boot()
1. API バージョンを表現するクラス (Value Object)を作る 2. RouteServiceProvider で Binding を(ついでに
pattern も)登録 3. Controller で利用する 19 Laravel でどう実装する?③ Route::get('{version}/posts', 'PostController@index'); public function index(ApiVersion $version, R... { // 特定のバージョンかどうか調べるには // $version->is() を使用 if ($version->is(1)) { // v1 の処理 } // バージョンの値を得たければ // $version->value() を使用 if ($version->value() <= 3) { // v2, v3 の処理 } // 以下略 } ↓
• Explicit Route Model Binding は Model 以外にも使い道がある! • API
バージョンを Value Object にするは良い工夫だと思う(自画自賛) • Application Layer の Value Object になる(特殊な例?) • (余談)そもそも API バージョニングって難しい 20 所感など
• 本当にその API にバージョンニングいる? • SSKDs (Small Set of Known
Developers) 向けならいらない? • c.f.) LSUDs (Large Set of Unknown Developers) • 後から足すことになるくらいなら、当面 v1 であってもひとまず…… • どのタイミングでバージョンを変える? • 後方互換が保てなくなったら?時間(1 年ごとなど)で区切る? • エンドポイント単位で更新?API 全体で更新? • バージョン指定なしを許容するか?許容する場合の挙動はどうするか? 21 余談:そもそも API バージョニング難しい問題 などなど……