2024.12.19
システムの穴を運用でカバーしようとしてミス多発… バグが大量発生、決算が合わない状態から業務効率化を実現するまで
openapi と swagger TS codegen(全1記事)
リンクをコピー
記事をブックマーク
菅原弘太郎氏(以下、菅原):それでは「OpenAPI GeneratorとTypeScriptによる型安全なスキーマ駆動開発」と題して、発表します。自己紹介します。2020年11月に、フロントエンドエンジニアとしてREADYFORに入社しました。岩手県在住で、フルリモートで勤務しています。ReactとTypeScriptが好きで、React Hook Formのメンバーなので、もしフォローしてくれる方がいれば、フォローしてください。
まずはフロントエンドとバックエンドの分離について話します。READYFORのサービスは、さまざまドメインが入り組んだ、1つのモノリスなサービスです。これがドメインごとに分離されたサービスを目指しています。
現状、フロントエンドとバックエンドの分離フェーズで、フロントエンドはTypeScriptとNext.jsを用いたSPA、バックエンドはREST APIという構成になっています。
私はちょうどフロントエンドとバックエンドの分離フェーズ中に入社しました。スキーマ駆動開発を実施している話は聞いていましたが、「はたして何だろう」という状態でした。
自分の3ヶ月前と同じような方がいるかもしれないので、今日は、スキーマ駆動開発とは何か、どんなメリットがあるのか、スキーマ駆動開発を実践する上でどんなツールを活用しているのか。3ヶ月、スキーマ駆動開発を実践してみた所感などを話せればと思います。これからスキーマ駆動開発を実践したい方の参考になれば幸いです。
まずはスキーマ駆動開発ついて説明します。SPAとAPI開発において、さまざまな悩みごとがあると思います。例えば、API仕様書のフォーマットが人によってバラバラだったり、仕様書と実装の乖離が発生したり。APIの実装を待たないとフロントの開発に着手できなかったり、あとはフロント側で想定していたリクエストやレスポンスが返ってこなかったりということがあるかと思います。
ここで、スキーマ駆動開発の出番です。まずスキーマ駆動開発のスキーマについて説明します。スキーマとは、ある定められた形式で記述したものです。Web APIの仕様定義と思ってもらって問題ありません。エンドポイントや、リクエストやレスポンスのデータ構造、値の型やフォーマットなどを定義したものを指します。
では、スキーマ駆動開発がどんなものかというと、Web APIの開発者と利用者、いわゆるバックエンドエンジニアとフロントエンドエンジニアでスキーマ設計を行い、スキーマを中心としたスキーマファーストな開発を行うことです。
これを実現するためには、さまざまなツールを活用する必要がありますが、スキーマが中心になって、ドキュメントの生成やコードの生成、モックサーバーの起動ができるようになります。
続いて、開発フローの違いについてです。スキーマ駆動開発以前では、APIが実装されてからフロントの実装に入るパターンがほとんどかと思います。これはフロント側でモックデータなどを用意すれば一応解決はできますがそもそも用意するのが面倒だったり手間がかかったりします。
これがスキーマ駆動開発を実践することでどうなるかというと、フロントとバックエンドでスキーマの設計を行って、コード生成ツールやモックサーバーを活用することで、APIの実装を待たずにフロント側で実装に入れます。
それでは、READYFORで活用しているツールの紹介です。まずはスキーマ定義から見ていきます。
知っている方も多いとは思いますが、READYFORではOpenAPIでスキーマを定義しています。Swaggerと聞けば知っている方がほとんどだと思うのですが、これはWeb APIを記述するためのフォーマットで、JSONやYAML形式での記述が可能です。READYFORではOpenAPI 3.0を使用しています。
イメージ的にはこのような感じになっています。左側がOpenAPIで定義したスキーマですが、「string型のpetIdのパラメータを、petsエンドポイントに対してGETリクエストすることによって、id・name・tagを含んだJSON形式で200レスポンスするよ」という意味合いになります。
続いてスキーマ定義の仕方ですが、ほとんどの場合はSwagger Editorを用いてスキーマを定義するのが一般的かと思います。これはどんなものかというと、左側でスキーマを編集しながら右側でプレビュー。いわゆる左側でスキーマを定義したものが、リアルタイムでAPIドキュメントとして可視化されて見れるエディタになっています。
また、ほかの選択肢としてStoplight Studioというものがあります。Swaggerとは違って、GUIです。そのため、OpenAPIのスキーマ定義についてあまり詳しくない人でも、ポチポチGUIをいじるだけでスキーマを定義できます。
Swagger Editorの画像は、このようなイメージです。
Stoplight Studioはこんな感じです。実際に触ってみたほうがいいと思います。
続いて、ドキュメントの自動生成ツールについての説明をします。これも知っている方がほとんどかと思いますが、Swagger UIを活用しています。先ほど見せたSwagger Editorのプレビュー側だと思ってもらって問題ありません。スキーマからドキュメントが生成されるので、信頼できます。
続いて、コード生成について見ていきたいと思います。READYFORでは、コード自動生成ツールにOpenAPI Generatorを使用しています。RubyやTypeScriptをサポートしていて、ほかにもJavaやPHPなどもサポートしています。
今回はDockerの例ですが、左の意味としては「openapi.ymlファイルをもとに、src/types/apiディレクトリに生成ファイルを出力する」というコマンドになります。ツリーを見てもらえばわかると思いますが、このように、APIクライアントやモデルが作成されます。
READYFORでは、ジェネレーターとして「typescript-fetch」を使用しています。
実際に生成されたファイルはこんな感じです。APIクライアントや、あとはリクエスト・レスポンスの型が生成されます。
続いて、スキーマから自動で型が生成されるので、リクエストやレスポンスの型にミスがない。いわゆる自前で定義すると、JSONのキーに間違いがあったりなどすると思いますが、そういうのがなくなって、型を信頼できます。
あとは、APIクライアントなどのコードが生成されるので、定型コードを記述するコストも減るんじゃないかなと思います。また、スキーマが変更された際もビルドエラーで修正箇所を把握できるので、おすすめです。
続いて、ハマりどころを紹介したいと思います。まず1点目としては、tagsを指定せずにスキーマを定義すると、APIクラス名が「DefaultApi」 という名前で生成されてしまいます。これを回避するには、ちゃんとtagsを指定しておいたほうがよいです。
続いてハマりどころ2なんですが、operationIdを指定せずにスキーマを定義すると、APIクラスのメソッド名やリクエストデータの型名が自動で生成されてしまいます。これもoperationIdを付与することによって、自分の意図した命名ができるようになります。
ハマりどころ3としては、components/schemasを使用せずにスキーマを定義すると、レスポンスデータの型名というのも自動で生成されるため、「InlineResponseXXX」という感じで、けっこうわかりづらい感じに生成されてしまいます。これも、ちゃんとcomponent/schemaで区切って生成することで、意図した型名で生成できるようになります。
続いて、モックサーバーの活用についてです。モックサーバーを活用することで、APIの実装を待たずにフロント側で開発に着手できるようになります。READYFORでは、Prismというモックサーバーを使用しています。先ほど紹介したStoplight Studioにも、モックサーバーとして統合されています。
コマンドとしてはこんな感じです。openapi.yaml、スキーマをもとにモックサーバーを起動できます。デフォルトでは、毎回同じデータを返すスタティックレスポンスを生成します。一応-dフラグというものがあり、--dynamicオプションを付与することで、毎回異なるデータをレスポンスすることも可能です。
Prismの強力な機能の1つとして、Preferヘッダーを渡すことでレスポンスの変更が可能になります。例えば、コードに対して404のようなステータスコードを付与してあげると、404でレスポンスできるようになるし、さらにスキーマで定義したexampleを指定することによって、そのexampleをレスポンスできるようになります。
あとはdynamicというのがあり、先ほどCLIで紹介した-dオプションと同じダイナミックレスポンスを有効化する機能も、ヘッダーに付与できるようになります。
あとはなにより、Cypressと相性が非常によいです。例えば「入力フォームのsubmitボタンを押して422エラーがレスポンスされたときに、エラーメッセージが表示されるか?」といったテストが簡単にできます。
先ほど紹介したPreferヘッダーを使用してあげることで、これを実現できます。Cypressではリクエストヘッダーをカスマイズできるので、APIにリクエストする前に、ヘッダーをカスタマイズしてリクエストを投げることによって、このエラーレスポンスを返せるようになる、という感じです。
続いて所感についてですが、まずよかったことから説明したいと思います。もうすでに説明していると思いますが、スキーマからAPIドキュメントが生成されるので信頼できます。これはスキーマがメンテナンスされている前提ですが、スキーマファーストに開発していれば信頼できるものになります。
また、TypeScriptのコードが生成されるため、型安全に開発できます。あとは、モックサーバーがかなり強力なので、効率的・テスタブルな開発が可能です。さらに、PR上でOpenAPIのスキーマをベースにバックエンドと認識を合わせられるので、非常に効率的でやりやすいです。
いいところばかりでなくつらいところもあって。これはスキーマ駆動開発というよりは、openapi-generator-cliの問題ですが。CLIによって生成されたコードで、型エラーが発生する場合があります。oneOfやallOfを使用すると、けっこう発生してしまいます。
あえてジェネレータで-gオプションを指定して「typescript-fetch」から「typescript-axios」に変更して試してみました。そうすると、正しいコードが生成できたりするので、改善の余地はありそうだと思っています。
続いて、生成される型が最善ではないところです。enumは、Enum型で出力されます。これは当たり前といえば当たり前なんですが、できればUnion型に出力するオプションが欲しいです。また、nullableなenumをスキーマで定義しても、出力される型としてはnullableになりません。
あとはdate/date-timeフォーマットで指定したものがDate型で出力されます。本来であればstring型にしてほしいところですが、typescript-fetchのみ、そういう感じになってしまいます。
一応--type-mappingsオプションで型をマッピングできるので、これでstring型にはできます。しかし、型が修正されてもAPIクラス側で型エラーが発生するので、ここはフォーマットを指定しない手段をとるしかないかなと思っています。
続いて、スキーマ駆動開発を実践した上で「こういうのを検討したほうがよさそう」ということを記載しています。
まず1点目が「OpenAPI Generatorによって生成されたAPIクライアントを使用するか、それとも型定義のみを使用するか?」です。生成されたAPIクライアントを使うのは非常に効率的ですが、当然それに依存することになります。フロントエンド 側の設計に対応できるかどうか、コードをちゃんと読んで、判断した上で使用するほうがよいかと思います。
続いて、ジェネレータをどれにするかの問題です。そのままtypescript-axiosを使っているならaxiosでもいいとは思いますが、型定義のみ使用する場合は、先に説明した出力される型定義との兼ね合いを見て決定したほうがよさそうだと感じています。
続いて、スキーマ駆動開発を実践してみて重要と感じたことです。これはもうスキーマファーストな上で最も重要だと思いますが、フロントエンドとバックエンドともに、スキーマからコードを生成しましょう、というところです。
仮にですが、フロント側のみスキーマからコードを生成しても、スキーマとAPIの実装に乖離が発生する可能性が高いです。最悪の場合、スキーマがメンテナンスされなくなってしまうので、避けたほうがよいでしょう。
いろいろ紹介しましたが、スキーマ駆動開発は、メリットがデメリットを遥かに上回ると思っています。興味をもった方は、ぜひ実践してみてください。ご清聴、ありがとうございました。
2024.12.20
日本の約10倍がん患者が殺到し、病院はキャパオーバー ジャパンハートが描く医療の未来と、カンボジアに新病院を作る理由
2024.12.19
12万通りの「資格の組み合わせ」の中で厳選された60の項目 532の資格を持つ林雄次氏の新刊『資格のかけ算』の見所
2024.12.16
32歳で成績最下位から1年でトップ営業になれた理由 売るテクニックよりも大事な「あり方」
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
PR | 2024.12.20
モンスター化したExcelが、ある日突然崩壊 昭和のガス工事会社を生まれ変わらせた、起死回生のノーコード活用術
2024.12.12
会議で発言しやすくなる「心理的安全性」を高めるには ファシリテーションがうまい人の3つの条件
2024.12.18
「社長以外みんな儲かる給与設計」にした理由 経営者たちが語る、優秀な人材集め・会社を発展させるためのヒント
2024.12.17
面接で「後輩を指導できなさそう」と思われる人の伝え方 歳を重ねるほど重視される経験の「ノウハウ化」
2024.12.13
ファシリテーターは「しゃべらないほうがいい」理由 入山章栄氏が語る、心理的安全性の高い場を作るポイント
2024.12.10
メールのラリー回数でわかる「評価されない人」の特徴 職場での評価を下げる行動5選
Climbers Startup JAPAN EXPO 2024 - 秋 -
2024.11.20 - 2024.11.21
『主体的なキャリア形成』を考える~資格のかけ算について〜
2024.12.07 - 2024.12.07
Startup CTO of the year 2024
2024.11.19 - 2024.11.19
社員の力を引き出す経営戦略〜ひとり一人が自ら成長する組織づくり〜
2024.11.20 - 2024.11.20
「確率思考」で未来を見通す 事業を成功に導く意思決定 ~エビデンス・ベースド・マーケティング思考の調査分析で事業に有効な予測手法とは~
2024.11.05 - 2024.11.05