API開発の最高のDXを求めて - NestJS+Prisma+AWS Copilot
最近、何度目かになる個人プロダクト開発をしようという思いつきからAPI開発をしてて、その際できるだけ低コストでDX(開発者体験)を追求してみようとやってみたら、結構いい感じにできて個人的にはまぁまぁ満足できました。
数年前から考えるとDX関連の進化はめざましく、ユニットテストやLint、フォーマッターなどがあるのはほぼ当たり前になってきました。ここからさらに数年後に見たときにまた大きく変化してるような気もするので、見比べるためにも備忘録がてら技術選定やツールの使い勝手について記録したいと思います。
技術選定
言語選定
DXってところを重視するとやはり静的型付は欲しい+多少なりとも使い慣れてる言語が良いなと思い、RustとTypescriptの2択にしました。
Rustは言語思想がめちゃくちゃ面白くて好きなので、今回もRustにしようかなぁとも思ったのですが、主流のORMのDiesleの型エラーが見辛かった経験と、作るもの的にOAuth周りのライブラリがTypescriptの方が枯れたライブラリも多そうだったので、今回はTypescriptを選びました。
フレームワーク選定
今回はある程度フルスタックよりなフレームワークが欲しかったので、利用者数も多いNestJSを採用しました。
- Typescriptのコンパイル周り、JestやPrettier、eslintが初期構築される
- OAuth2関連ライブラリなどとも相性がよい
- DIで実装するためテスト書きやすそう
- コマンドからファイル生成するなどRailsよりな体験もある
ORMはPrismaにしました。
開発中の体験
実装中
nest g co hoge
で新規ファイルを作成し、スキーマいじってprisma migrate dev --preview-feature
などでマイグレーション準備して・・・など、NestJS+PrismaならRailsの開発体験とほぼ違いはなかった気がします。
NestJSはDIを基本思考としているので、テストも書きやすくてよかったです。
コミットフック
huskyでLint、フォーマッタ、ユニットテストを回す形にしました。
以下は.husky/pre-commit
です。
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
lint-staged
pretty-quick --staged
yarn test
基本的に修正漏れはコミットフックで最低限守れる形になりました。
とはいえ、だいたいテストしながらプロダクションコード実装するからこれはなくても正直成り立つ気はするけど、心理的にもチェックポイントあるのは安心感あって良かったです。
プルリクフック
Github ActionsでE2E実行とユニットテストのカバレッジレポートをプルリクにコメントするようにしました。
カバレッジの投稿は以下を利用したら簡単でした。
E2Eはdocker-composeを基に新規でデータベースをマイグレーションして、擬似リクエストに対するテストなので実際の挙動にかなり近いテストをデプロイ前にできるので、マージ前の安心感もこれでだいぶ強くなりました。
ドキュメンテーション
NestJSではOpenAPI系のライブラリもあり、以下の手順に沿ってでコレータを適宜書くだけで自動で仕様書が出来上がりました。
これが本当に良くできてて、ソース上に書くためそのメソッド自体のコメントにもなるしOpenAPIとして出力もされるので、「仕様書の修正漏れ」がかなり発生しづらい気がしています。
デプロイ体験
インフラ選定
APIデプロイ先はHerokuしか触ったことなかったのですが、コンテナデプロイが簡単と聞いて勉強がてらAWS Copilotを利用することにしました。
AWS App Runner使ってみたかったのですが、まだ任意のVPC設定が未対応のためパブリックアクセス不可なデータベースへアクセスできず、今回はECS(Fargate)でデプロイしてみました。
デプロイ
AWS CLIのクレデンシャル情報の設定が必要ですが、設定後は初期構築からデプロイまで以下のみで終了。
copilot app init --domain example.com
copilot env init --name production
copilot svc init --name app
copilot svc deploy --name app --env production
監視
AWS Copilotがデプロイ時にヘルスチェックも行ってくれました。
ただし、デプロイ直後はヘルスチェックに失敗するバグ?があるようで、issue立てたら現在start_period
という設定を検討・実装中とのことでした。
デプロイ自動化
本当はAWS Copilotにはpipelineというデプロイ自動化を構築するコマンドもあるんですが、現状プライベートリポジトリには未対応のため、今回は見送りました。
頑張ればGithub ActionsとCopilotでやれなくもない気がするんですが、そのうち対応されそうor App RunnerのVPC対応が終わったらそっちに移行した方が簡単そうなので頑張らずしばらくMacからデプロイすることにしました。
まとめ
Typescipt、NestJS、Prisma、AWS Copilotで以下が簡単に構築できました。
- 実装はnest cliでファイル生成、prisma cliでマイグレーション
- コミットフックでLint、ユニットテストとフォーマッタ適用
- プルリクフックでカバレッジレポートとE2E
- NestJSのデコレータでOpenAPIに関するコメントをソース上に残して仕様書の自動出力
- デプロイはAWS Copilotで1コマンドで完了
Discussion