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
Shohei Okada
September 26, 2018
Programming
1
34
Laravel で API バージョニングを実装するなら
2018-09-26 開催の「第130回 PHP勉強会@東京」におけるLT資料です
https://phpstudy.doorkeeper.jp/events/79982
Shohei Okada
September 26, 2018
Tweet
Share
More Decks by Shohei Okada
See All by Shohei Okada
たった 1 枚の PHP ファイルで実装する MCP サーバ / MCP Server with Vanilla PHP
okashoi
1
360
どうして手を動かすよりもチーム内のコードレビューを優先するべきなのか
okashoi
3
1.5k
パスワードのハッシュ、ソルトってなに? - What is hash and salt for password?
okashoi
3
230
設計の考え方 - インターフェースと腐敗防止層編 #phpconfuk / Interface and Anti Corruption Layer
okashoi
11
4k
"config" ってなんだ? / What is "config"?
okashoi
0
1.3k
ファイル先頭の use の意味、説明できますか? 〜PHP の namespace と autoloading の関係を正しく理解しよう〜 / namespace and autoloading in php
okashoi
4
1.7k
MySQL のインデックスの種類をおさらいしよう! / overviewing indexes in MySQL
okashoi
0
940
PHP における静的解析(あるいはそもそも静的解析とは) / #phpcondo_yasai static analysis for PHP
okashoi
1
640
【PHPカンファレンス沖縄 2023】素朴で考慮漏れのある PHP コードをテストコードとともに補強していく(ライブコーディング補足資料) / #phpcon_okinawa 2023 livecoding supplementary material
okashoi
3
2k
Other Decks in Programming
See All in Programming
Reactの歴史を振り返る
tutinoko
1
180
Amazon Q CLI開発で学んだAIコーディングツールの使い方
licux
3
180
WebAssemblyインタプリタを書く ~Component Modelを添えて~
ruccho
1
770
『リコリス・リコイル』に学ぶ!! 〜キャリア戦略における計画的偶発性理論と変わる勇気の重要性〜
wanko_it
1
500
What's new in Adaptive Android development
fornewid
0
140
QA x AIエコシステム段階構築作戦
osu
0
270
「リーダーは意思決定する人」って本当?~ 学びを現場で活かす、リーダー4ヶ月目の試行錯誤 ~
marina1017
0
210
ワープロって実は計算機で
pepepper
2
1.3k
新しいモバイルアプリ勉強会(仮)について
uetyo
1
250
Webinar: AI-Powered Development: Transformiere deinen Workflow mit Coding Tools und MCP Servern
danielsogl
0
110
大規模FlutterプロジェクトのCI実行時間を約8割削減した話
teamlab
PRO
0
470
DataformでPythonする / dataform-de-python
snhryt
0
160
Featured
See All Featured
Optimizing for Happiness
mojombo
379
70k
Navigating Team Friction
lara
188
15k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
26
3k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
251
21k
Six Lessons from altMBA
skipperchong
28
3.9k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
8
450
Visualization
eitanlees
146
16k
Large-scale JavaScript Application Architecture
addyosmani
512
110k
Unsuck your backbone
ammeep
671
58k
Music & Morning Musume
bryan
46
6.7k
GraphQLの誤解/rethinking-graphql
sonatard
71
11k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
29
1.8k
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 バージョニング難しい問題 などなど……