Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
PHPのアノテーション(アトリビュート)からOpenAPIのドキュメントを出力し、レスポンスも...
Search
kalibora
November 08, 2024
Programming
270
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
PHPのアノテーション(アトリビュート)からOpenAPIのドキュメントを出力し、レスポンスもそれを元にシリアライズすることで仕様と実装を乖離させず、色々楽できたよって話
kalibora
November 08, 2024
More Decks by kalibora
See All by kalibora
QA環境で誰でも自由自在に現在時刻を操って検証できるようにした話
kalibora
0
580
Swagger (OpenAPI) と PHPStan で REST API でも型安全っぽく使う
kalibora
0
3.6k
Symfony2 の Functional Test のメモリ使用量と実行時間を削減した話
kalibora
0
28
WebAudioと音の話
kalibora
0
460
Other Decks in Programming
See All in Programming
Railsバージョンを4倍にした話
optim
0
810
AI時代のFlutter品質設計 — アプリ品質を守るQuality Layers
omatty198
0
210
自サークルのIdPからログアウトできるようになるまで
taiseiue
1
150
Snowflake Openflow Connector利用の勘所 / 20261024developersio2026tokyo-snowflake-openflow
kasacchiful
PRO
0
220
HTML-in-Canvasで作る未来のWeb UI表現
clockmaker
5
5.9k
気持ちぃ〜角丸 Squircle
ryu1013
0
360
クラウドゲーミングのパフォーマンス最適化に挑む / Cloud Gaming Performance Tuning
vivion
0
300
Modernizing iOS Apps
seyfoyun
0
130
【加筆修正版】Laravel のアプリケーションをどこにデプロイするか #phpcon_ehime
akase244
0
160
PyConTW 2026 - AI Coding 不只是工具升級, 區域醫院醫療資訊系統協作開發與資訊團隊轉型實踐
cclai999
0
210
複雑なUIコンポーネントとの ⻑い付き合い⽅:波及するバグからテスト戦略を経て、安全な再設計へ
mixplace
0
480
AIがコードを書いてくれる時代、我々は何を確かめるのか
yosuke_furukawa
PRO
12
5k
Featured
See All Featured
Navigating Weather and Climate Data
rabernat
0
560
Joys of Absence: A Defence of Solitary Play
codingconduct
1
560
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.7k
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.4k
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
470
Context Engineering - Making Every Token Count
addyosmani
9
1.2k
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.5k
The World Runs on Bad Software
bkeepers
PRO
72
12k
Navigating the Design Leadership Dip - Product Design Week Design Leaders+ Conference 2024
apolaine
2
490
The Pragmatic Product Professional
lauravandoore
37
7.5k
Accessibility Awareness
sabderemane
1
260
Statistics for Hackers
jakevdp
799
230k
Transcript
PHP のアノテーション(アトリビュー ト)からOpenAPI のドキュメントを出 力し、レスポンスもそれを元にシリア ライズすることで仕様と実装を乖離さ せず、色々楽できたよって話 Toshiyuki Fujita (@kalibora)
2024/11/08
最初に 今回の発表は2019 年11 月の KyotoLT 第25 回 で喋った Swagger (OpenAPI)
と PHPStan で REST API でも型安全っぽく使う の焼き 直しです でも多分誰も知らないと思うのここでも話します 現状はOpenAPI は3 系ですが、昔の話なので2 系(まだSwagger と呼 ばれてた時代)が話のベースとなっていますがご容赦ください 2024/11/11 追記 この発表後に現代では API Platform を使えばもっといい感じに できると教えていただきました なのでこの資料は過去の歴史としてご笑覧ください
自己紹介 Toshiyuki Fujita ID: @kalibora 20 年くらいPHP いじってご飯を食べてます Yahoo! JAPAN
-> (Crocos) -> Otobank -> RABO 今回のは Otobank 時代にやってた話です Symfony と Doctrine が好きです
OpenAPI とは - (WebAPI の仕様書くツールって、昔はいろいろあったけど結局もう これが勝ったという認識でよろしいか?) OpenAPI Specification (以前はSwagger Specification
として知ら れていた)は、Web サービスを記述、生成、消費[ 訳語疑問点] 、 可視化するための機械可読なインターフェース記述言語の仕様で ある[1] 。 See: https://ja.wikipedia.org/wiki/OpenAPI_Specification “ “
突然ですが・・・ OpenAPI の仕様書くのって ダルいですよね?
OpenAPI の仕様書くのってダルいですよね? swagger: "2.0" info: version: "1.0.0" description: "こういうやつですね" title:
"Swagger Petstore" termsOfService: "http://swagger.io/terms/" contact: email: "
[email protected]
" license: name: "Apache 2.0" url: "http://www.apache.org/licenses/LICENSE-2.0.html" host: "petstore.swagger.io" basePath: "/v2"
OpenAPI の仕様を書くための手段 Swagger Editor https://editor.swagger.io/ ブラウザベースで記述できるエディター swagger-php https://github.com/zircote/swagger-php PHP のアトリビュート(もしくはアノテーション)を使って仕様
を記述できる これを使って楽する!! (※これ調べたの昔なので最近はもっと色々増えてるかもね!)
swagger-php(v2) の使用例 例えば User というクラスに name プロパティがあって、 これをAPI のレスポンスのI/F として定義したい場合、
/** * @SWG\Definition() */ class User { /** * ユーザー名 * @SWG\Property() */ public string $name; }
出力結果 swagger: '2.0' definitions: User: properties: name: description: ユーザー名 type:
string
便利! でもデフォルトのswagger-php だと 不便な点があった
デフォルトのswagger-php だと不便な点 getter などのアクセサに対応していない 実際の業務で使っているエンティティクラスは private なプロパ ティ + getter
な構成が多いのでそのままだとうまく使えない (※2024/11/08 現在ではできるようになったのか未確認です) ので、自前で swagger-php を拡張して対応した
自前で swagger-php を拡張して getter に対応 /** * @SWG\Definition() */ class
User { private sring $name; /** * ユーザ名 * @SWG\Property() */ public function getName() : string { return $this->name; } }
出力結果 先ほどとほぼ同じ結果のOpenAPI 仕様が書き出されるように拡張。 return type hint を使い、nullable でないものは required に。
swagger: '2.0' definitions: User: required: - name properties: name: description: ユーザー名 type: string
いい!! けどせっかくなら そのままAPI の挙動にも反映したい
API の挙動にも反映したい そもそもだけど、アノテーション(アトリビュート)書いたらその ままAPI の挙動に反映できたら便利 アノテーション(アトリビュート)から 仕様(OpenAPI 仕様の出力結果) 実装(実際にレスポンスとして返す値) この両方に影響を与えたい
オブジェクトから配列に変換する処理を書いた ようするにシリアライザー(ノーマライザー?)を実装した。 /** * @SWG\Definition() */ class User { private
sring $name; /** * ユーザ名 * @SWG\Property() */ public function getName() : string { return $this->name; } } 先ほどと同じこういうクラスの定義から、
連想配列に変換 SwaggerSerializer という自前で実装したクラスが @SWG\Property アノ テーションを読み取り、連想配列にする。 $user = new User('Otobank
Taro'); var_dump($swaggerSerializer->serialize($user)); // [name => 'Otobank Taro'] これにより、 @SWG\Property を定義した getter は API のレスポンスの I/F としても露出するし、実際にAPI のレスポンスとしても返却される ようにした。
PHPStan と組み合わせる
PHPStan と組み合わせる PHPStan と組み合わせれば、サーバー(API )側とクライアント側 との間でAPI 呼び出しをしても型安全にできる
例えばこんなケース
API 側のエンティティクラス class Campaign { /** * キャンペーン開始日時 * @SWG\Property()
*/ public function getStartedAt() : \DateTimeInterface { /* 実装は省略 */ } /** * キャンペーン終了日時 * @SWG\Property() */ public function getEndedAt() : ?\DateTimeInterface { /* 実装は省略 */ } }
出力されるOpenAPI 仕様書 swagger: '2.0' definitions: Campaign: required: - startedAt properties:
startedAt: description: キャンペーン開始日時 type: string format: date-time endedAt: description: キャンペーン終了日時 type: string format: date-time x-nullable: true # ←ここに注目
OpenAPI 仕様書から自動生成されたクライアント側のクラス class Campaign implements ModelInterface, ArrayAccess { /** *
Gets started_at * @return \DateTime */ public function getStartedAt() { /* 実装は省略 */ } /** * Gets ended_at * @return \DateTime|null */ public function getEndedAt() { /* 実装は省略 */ } } ※ クライアントの自動生成は swagger-api/swagger-codegen をベースに x-nullable を うまく解釈できるようにテンプレートはカスタマイズしています
クライアント側のPHPStan でのチェック クライアント側で自動生成されたクラスでも getEndedAt() が nullable なので、API を呼び出す側の実装者が、うっかりキャンペーンの終了日 時が nullable
である。 という仕様を知らなかった(読み取りそこねた)としても、自動的に エラーを検出できる。
さらにいろんなことに活用できる
その他の活用事例 public なAPI がセンシティブな情報を返していないことをCI で担保する 仕様と実装が乖離していないため、仕様であるyaml(or json) ファイルを機械 的にパースして特定のキーワード(password など)がレスポンスにあった
らCI で落とす 詳しくは: API が不必要にセンシティブなデータを返していないことをCI で 担保する - OTOBANK Engineering Blog API のI/F 変更があったらサマリをGitHub Actions でPR に書いてもらう OpenAPITools/openapi-diff を使って仕様の差分を取る さらに(プロパティが削除されるなどの理由で)後方互換性が崩れていたら CI で落とす
おしまい