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
NestJSのコードからOpenAPIを自動生成する際の最適解を探す
Search
Tatsuya Asami
March 17, 2025
Programming
0
350
NestJSのコードからOpenAPIを自動生成する際の最適解を探す
Tatsuya Asami
March 17, 2025
Tweet
Share
More Decks by Tatsuya Asami
See All by Tatsuya Asami
終わってる風終わってないタスクが自分の首を締めた話
astatsuya
0
440
Other Decks in Programming
See All in Programming
The Evolution of Enterprise Java with Jakarta EE 11 and Beyond
ivargrimstad
0
550
202507_ADKで始めるエージェント開発の基本 〜デモを通じて紹介〜(奥田りさ)The Basics of Agent Development with ADK — A Demo-Focused Introduction
risatube
PRO
5
1.2k
NEWT Backend Evolution
xpromx
1
160
それ CLI フレームワークがなくてもできるよ / Building CLI Tools Without Frameworks
orgachem
PRO
11
3k
0から始めるモジュラーモノリス-クリーンなモノリスを目指して
sushi0120
0
170
11年かかって やっとVibe Codingに 時代が追いつきましたね
yimajo
0
210
AIコーディングエージェント全社導入とセキュリティ対策
hikaruegashira
15
8.5k
MCPを使ってイベントソーシングのAIコーディングを効率化する / Streamlining Event Sourcing AI Coding with MCP
tomohisa
0
190
Reactの歴史を振り返る
tutinoko
1
150
ZeroETLで始めるDynamoDBとS3の連携
afooooil
0
130
Understanding Kotlin Multiplatform
l2hyunwoo
0
230
Google I/O Extended Incheon 2025 ~ What's new in Android development tools
pluu
1
200
Featured
See All Featured
Into the Great Unknown - MozCon
thekraken
40
1.9k
Testing 201, or: Great Expectations
jmmastey
43
7.6k
How to Think Like a Performance Engineer
csswizardry
25
1.8k
Raft: Consensus for Rubyists
vanstee
140
7k
Making the Leap to Tech Lead
cromwellryan
134
9.4k
For a Future-Friendly Web
brad_frost
179
9.8k
Gamification - CAS2011
davidbonilla
81
5.4k
Facilitating Awesome Meetings
lara
54
6.5k
Build your cross-platform service in a week with App Engine
jlugia
231
18k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
Building Adaptive Systems
keathley
43
2.7k
Java REST API Framework Comparison - PWX 2021
mraible
31
8.7k
Transcript
© Commune Inc. All rights reserved NestJSのコードから OpenAPIを 自動生成する際の最適解を探す 2024/03/17
NestJS meetup #6 浅見 達也@astatsuya1 1
© Commune Inc. All rights reserved 浅見 達也 (@astatsuya1) •
仕事 ◦ コミューン株式会社 SuccessHub事業部 ▪ 2022年7月~2024年3月 CommuneのWebエンジニア ▪ 2024年4月~ SuccessHubのWebエンジニア • ペット ◦ デグー 自己紹介 2
© Commune Inc. All rights reserved 3 チームの生産性を圧倒的に向上し、カスタマーサクセス組織に成果をもたらす 顧客に関するあらゆる重要な 情報や健康状態を一元管理
テックタッチの工数で ハイタッチの効果を実現 顧客の状態に応じた個別最適な アクションを実行管理
© Commune Inc. All rights reserved • NestJSのコードからOpenAPIを自動生成する際の最適解を探す ◦ これまでやってきて苦戦したことを共有
◦ 道半ばながら辿り着いた最適解を共有 今日の発表内容 4
© Commune Inc. All rights reserved • 技術構成 ◦ バックエンドはNestJS(monorepo,
SWC)でREST API ◦ class-validator, class-transformerを使ってAPIリクエストのバリデーション や変換を行っている ◦ @nestjs/swaggerを使ってソースコードからOpenAPIを出力 ◦ フロントエンド(今回関係ない) ▪ Orvalを使ってOpenAPIからフロントエンドで使用するコード(型定義、データフェッチ、モックサーバー)を 自動生成 ▪ ブラウザからNestJSにHTTPリクエスト(BFFはない) 前提となる技術構成 5
© Commune Inc. All rights reserved 過去やってきたことを紹介します 1. @nestjs/swagger CLI
Pluginの導入をチャレンジ(失敗) a. 実装中にローカルサーバーがエラーで止まりまくる 2. @nestjs/swagger CLI Pluginを使わず、手動でデコレータを付ける(採用) a. 仕組みは出来たが不満あり 今までやってきた OpenAPIの自動生成への取り組み 6
© Commune Inc. All rights reserved ParametersとRequest bodyの出力 4. @nestjs/swagger
CLI Pluginを使わず、手動でデコレータを付ける 7 • リクエストボディ、リクエストパラメータは元々 dtoがあったので、ひたすら @ApiPropertyを つけるのみ • この例は単純だが、他の dtoなどをimportし て型定義に使っている場合はもっと色々記 述する ◦ 結構重要なポイントだが今回は割愛
© Commune Inc. All rights reserved Responseの出力のためにClassSerializerを剥がす 4. @nestjs/swagger CLI
Pluginを使わず、手動でデコレータを付ける 8 • ClassSerializerはクラスインスタ ンスをプレーンオブジェクトに変 換してくれる • 元々エンティティに変換処理のた めのデコレータをつけることがみ んな微妙だと思っていた(コント ローラーで行うべき処理) ので、あまりためらいなく剥がし た
© Commune Inc. All rights reserved Responseの出力のためにdto作成 4. @nestjs/swagger CLI
Pluginを使わず、手動でデコレータを付ける 9 • レスポンスは新たにレスポンス用の dtoを作 成 • レスポンスではバリデーションを行わない ので、OpenAPIのためだけに書いている
© Commune Inc. All rights reserved Response出力のためにコントローラーにデコレータを追加 4. @nestjs/swagger CLI
Pluginを使わず、手動でデコレータを付ける 10 • コントローラーの関数に @ApiOkResponseのデコレータを 追加 ◦ これをつけるとOpenAPIの Responseが出力される • コントローラーの関数の戻り値の型 にdtoを指定することで型安全にす る ◦ dtoにあるプロパティを書き忘 れたらエラーになる
© Commune Inc. All rights reserved 記述が多くて面倒だが、理論上完璧 4. @nestjs/swagger CLI
Pluginを使わず、手動でデコレータを付ける 11
© Commune Inc. All rights reserved • OpenAPIのためのデコレータの記述を間違えがち • 間違っていてもIDE上でエラー等は出ないので、気をつける、ちゃんと確認
する以外のソリューションがない • フロントエンド開発中にミスに気がつくと、バックエンドのコード修正をまず やらないといけないのが面倒 ◦ OpenAPIからフロントエンドのコードを自動生成をしているため、フロ ントエンドの型定義は手動で直せない 半年ほど運用してみて 12
© Commune Inc. All rights reserved かなり単純な記述でも忘れがち 今まで取り組んできたことの流れ 13
© Commune Inc. All rights reserved • @nestjs/swaggerのCLI Plugin導入に再チャレンジ ◦
NestJSのドキュメント通りに実装したところ ▪ 上手く出来ている • ローカルサーバーは動いている • OpenAPIのParameters, Request body, Responseはおおよそ出力されている様 子 ▪ 上手く出来ていない • 12件型エラーが出ている • コード変更しているとたまに型エラーが出る • ローカルサーバーの起動時間が約 3秒→約27秒になった 改善に向けて 14
© Commune Inc. All rights reserved ◦ 全て同じファイルにdtoが複数ある場合だった ▪ 単にファイル分割で対応完了
これでエラーがなくなった! 12件型エラーが出ている 15
© Commune Inc. All rights reserved • ファイル追加や削除、変数名を変更した場合にエラーが出やすい ◦ ローカルサーバーは止まっていないようなのでエラーを無視すれば開発自
体は出来るが気になる • エラー自体が起きないようにするのは難しそう エラーが起きたら復旧出来るようにする コード変更しているとたまに型エラーが出る 16
© Commune Inc. All rights reserved • エラーを起こしているmetadata.tsを上書きする単純なスクリプトを作成 ◦ metadata.tsはCLI
Pluginを使うと生成されるOpenAPIのためのファイル ◦ エラーが起きたらこのスクリプトを実行してリセット スッキリ解決はしてないけど、これでストレスはかなり軽減 コード変更しているとたまに型エラーが出る 17
© Commune Inc. All rights reserved • 流石に許せない ◦ SWCを入れる前と同じくらい時間がかかっている
OpenAPIを立ち上げないコマンドと、OpenAPIを立ち上げるコマンドを用意する ローカルサーバーの起動時間が約 3秒→約27秒になった 18
© Commune Inc. All rights reserved • OpenAPIを生成するときとしないときのnest-cliを作成 ◦ nest-cli.json(しない)とnest-cli-openapi.json(する)を作成
◦ コマンド実行時にファイルパスを指定する ローカルサーバーの起動時間が約 3秒→約27秒になった 19 SwaggerModule
© Commune Inc. All rights reserved • OpenAPIを使わない場合はSwaggerModuleも読み込まない ◦ metadata.tsを読み込まなければ速度はあまり変わらないが、不完全な
OpenAPIが見たいこと はない、混乱の元なので全部読み込まない • npm scripts(コマンド長い) ローカルサーバーの起動時間が約 3秒→約27秒になった 20 SwaggerModule
© Commune Inc. All rights reserved コマンドの使い分け • 普段のバックエンド開発では OpenAPIは生成しないで立ち上げ
◦ バックエンド開発中は OpenAPIをあまり見ないため ◦ ローカルサーバーは安定して欲しい、何度も起動するので速度も重要 • OpenAPIを見たい時、変更するときは OpenAPIを生成して立ち上げ ◦ 実装中にエラーが出たときはリセットコマンドで回避可能 ◦ プロダクションビルド (nest build)も遅くなるが、サーバーの起動速度はほぼ変わらなかったの で問題なし 少し苦しいがなんとか課題解決! ローカルサーバーの起動時間が約 3秒→約27秒になった 21 SwaggerModule
© Commune Inc. All rights reserved • dtoにあるOpenAPIには不要なプロパティに @ApiHidePropertyをつけていく ◦
toNameのような変換関数が主に不要な値 • 不要になった@ApiPropertyを消していく ◦ あっても問題ない。@ApiPropertyに記述してある値 が優先的に使われる ◦ 型定義が複雑な場合は引き続き指定する必要があ る 残りの作業は @ApiHidePropertyをつけていく 22
© Commune Inc. All rights reserved これで一通り完了! 23
© Commune Inc. All rights reserved ◦ dtoは1ファイルに1つのみ記載する ◦ dtoの各プロパティには基本的に@ApiPropertyをつけない。上手く出力されな
い場合にのみ@ApiPropertyを使って正しい値を自分で記述する ◦ dtoにあるOpenAPIには出力したくないプロパティには@ApiHidePropertyをつ ける 開発時に気にすることまとめ 24
© Commune Inc. All rights reserved • OpenAPIのために技術的な選択が必要だった ◦ ClassSerializerを剥がしたが、剥がしたくない場合は積んでいたかも
• コードからドキュメント(OpenAPI)が自動生成される一番嬉しい状態が作れた • 快適なローカル開発環境との両立は許容できる 総じて満足 道半ばながら辿り着いた最適解振り返り 25
© Commune Inc. All rights reserved NestJSとOpenAPIの話は以上です 最後に本件と関係ないけど気になっていること 26
© Commune Inc. All rights reserved • NestJSでそこまでコード量が多くないのにモジュールの読み込みに結構時間が かかるのをどう対処しているのか •
漏れがなく、負荷が少ない操作ログの設計 • MySQL, Prismaを使ってマルチテナントの実装する場合の工夫 • Visual Regression Testで何をどこまで確認しているか この後の懇親会で相談させてください!! 最後に本件と関係ないけど気になっていること 27
募集中の求⼈はこちら カジュアル⾯談も 実施しています! コミューン株式会社では共に働く仲間を募集中です ありがとうございました