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
PHPのアノテーション(アトリビュート)からOpenAPIのドキュメントを出力し、レスポンスも...
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
kalibora
November 08, 2024
Programming
0
220
PHPのアノテーション(アトリビュート)からOpenAPIのドキュメントを出力し、レスポンスもそれを元にシリアライズすることで仕様と実装を乖離させず、色々楽できたよって話
kalibora
November 08, 2024
Tweet
Share
More Decks by kalibora
See All by kalibora
QA環境で誰でも自由自在に現在時刻を操って検証できるようにした話
kalibora
0
460
Swagger (OpenAPI) と PHPStan で REST API でも型安全っぽく使う
kalibora
0
3.3k
Symfony2 の Functional Test のメモリ使用量と実行時間を削減した話
kalibora
0
14
WebAudioと音の話
kalibora
0
440
Other Decks in Programming
See All in Programming
例外処理とどう使い分ける?Result型を使ったエラー設計 #burikaigi
kajitack
16
6.1k
Claude Codeと2つの巻き戻し戦略 / Two Rewind Strategies with Claude Code
fruitriin
0
150
「ブロックテーマでは再現できない」は本当か?
inc2734
0
1.1k
izumin5210のプロポーザルのネタ探し #tskaigi_msup
izumin5210
1
150
QAフローを最適化し、品質水準を満たしながらリリースまでの期間を最短化する #RSGT2026
shibayu36
2
4.4k
CSC307 Lecture 04
javiergs
PRO
0
660
AIエージェントのキホンから学ぶ「エージェンティックコーディング」実践入門
masahiro_nishimi
6
690
登壇資料を作る時に意識していること #登壇資料_findy
konifar
4
1.7k
日本だけで解禁されているアプリ起動の方法
ryunakayama
0
290
OSSとなったswift-buildで Xcodeのビルドを差し替えられるため 自分でXcodeを直せる時代になっている ダイアモンド問題編
yimajo
3
630
2026年 エンジニアリング自己学習法
yumechi
0
140
AI Agent の開発と運用を支える Durable Execution #AgentsInProd
izumin5210
7
2.3k
Featured
See All Featured
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
1.8k
What the history of the web can teach us about the future of AI
inesmontani
PRO
1
440
WENDY [Excerpt]
tessaabrams
9
36k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.3k
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
350
Rails Girls Zürich Keynote
gr2m
96
14k
sira's awesome portfolio website redesign presentation
elsirapls
0
150
How to train your dragon (web standard)
notwaldorf
97
6.5k
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
110
What’s in a name? Adding method to the madness
productmarketing
PRO
24
3.9k
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
3.9k
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
150
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 で落とす
おしまい