概要
NestJS を初めて触る人向けの、フレームワーク理解を深めるための備忘録。
NestJS の基本的な仕組みを知るために、モジュール/コントローラ/サービス の基本3概念について紹介。
# | 内容 |
---|---|
1 | 基本概念・環境構築 |
2 | 基本3概念、モジュール/コントローラ/サービス とは(今回) |
3 | spec とは何か? |
前提
- オブジェクト指向の基礎(クラスなどの概念)がわかること
- 「Web サーバ」が何かを知っていること
- 「REST API」の基礎概念がわかること
初期ファイル構成
NestJS はバックエンドフレームワークなので、主に API として https://xxxxx
と呼ばれた後に動作する部分を担当する。
最初に、プロジェクト作成コマンドでいくつかのファイルが自動生成されるが、その中で知っておくべき事は以下の4点。
- main.ts ファイル(=エントリーポイント)
- module(モジュール)ファイル
- controller(コントローラ)ファイル
- service(サービス)ファイル
各ファイルの作り方
nest コマンドで自動生成する。
NestJS のプロジェクトディレクトリ直下で、自動生成コマンド nest generate
または省略形の nest g
を実行する。
# モジュール作成
nest g module モジュール名
# コントローラ作成
nest g controller コントローラ名
# サービス作成
nest g service サービス名
実行すると、自動でディレクトリとファイルを作成してくれる。この時 .spec.ts
も自動生成されるが、今回は無視して構わない。
基本3概念
※「基本3概念」は、私が勝手にそう呼んでるだけで、もともとそんな言葉はございません🙏
NestJS は基本的に 「モジュール(module)」「コントローラ(controller)」「サービス(service)」 の3つのクラスで構成され、以下のような関係になっている。
- コントローラ:APIで呼ばれる時のリクエストと、返却する時のレスポンスを担当する。ここでは細かい処理(いわゆるビジネスロジック)は書かない
- サービス:四則演算処理や、DB周辺処理などを書くところ。コントローラから呼び出されて動く
- モジュール:コントローラとサービスを入れる箱。特に処理などは書かない
基本は上記の3つで API として動くのが NestJS の主な構成。しかし、これだけだとシンプルすぎるので、もう少し掘り下げて処理フローをまとめると下図のとおり。
NestJS は、まず最初に「エントリーポイント」と呼ばれる部分が起動する。
ここでは簡易の Webサーバ として、main.ts
内に指定したポート番号でアプリケーションが起動し、https://example.com:ポート番号
という API リクエストを受け付けられる状態になる(NestJS のデフォルトポート番号は "3000"。番号や設定によって、変更・省略可能)。
次に、コントローラが呼ばれる。
API リクエストの 「エンドポイント」 と 「HTTPメソッド」 が、コントローラ内に書いた定義と一致すると、中の関数が呼ばれる。
エンドポイント とは、https://example.com:3000/users
の /users
部分後にくる文字列のこと。
HTTPメソッド は、リクエストの呼出方式「GET/POST/PUT/DELETE」などのこと。
その後は、サービス処理が呼ばれて、その処理結果を再びコントローラが返却して終わり。これが NestJS の基本的な構造と処理フローであり、API を簡単かつシンプルに書ける。
具体的な API 処理フロー例
上図を参考に、処理フローの具体例を記載する。
- 『GET
https://example.com:3000/users
』で API 実行-
/users
を担当するコントローラ(例: UsersController)が呼ばれる -
GET
メソッドを担当しているコントローラ内の関数が呼ばれる - コントローラと同じモジュールにセットされているサービス(例: UsersService)が呼ばれる
- サービス内で、DB からデータを持ってきて加工などする
- 処理結果を、コントローラを通じて、リクエスト元に返却する
-
これが『POST ~~/users
』『GET ~~/users/123
』等で呼ばれたりしても、コントローラ内のそれぞれに対応した関数を用意しておけば、それらが呼ばれて上記と同様の処理フローとなる。
名前の決め方
基本的には、DB内にある情報を扱う場合は「人物」「組織・部署名」「材料」など、複数あることが前提のデータリソースを扱うことが多い観点から、英単語の 複数形 で命名する。
例: ユーザ情報を扱う API
🙆♂️正: users
🙅♀️誤: user
モジュール名やコントローラ名も「UsersXxx」となる。
ただし、認証処理(Auth)など一部の場合は複数形でなくて良い。
モジュールはネストできる
モジュールファイルには、他のモジュールファイルを何個でも追加することができる。
なので、「1つのモジュールの中に複数のモジュールをぶら下げる」 とか 「Aモジュールの下にBモジュール、Bモジュールの下にCモジュール」 ということができる。
そもそも、NestJS には appModule.ts
という親モジュールファイルが必ず存在し、独自のファイルはその下にぶら下げていくのが基本的な開発の仕方。つまり下図のようなイメージ。
上図の例では、/users
というエンドポイントは Users Module が担当するようにファイルを用意し、 /groups
や /activities
など、呼ばれるエンドポイント毎にモジュールを作成している。
新たに必要な API が増えたらモジュールを追加し、呼ばなくなった不要な API はモジュールは捨てるだけで済むので、アプリケーションのスケール(拡張と縮小)がとても簡単になっている。
構成の作り方を、ごく簡単にまとめると下記の通り。
- エンドポイント
/
で呼ばれる処理-
app.module.ts
配下のコントローラ/サービスにまとめる
-
- エンドポイント
/
以外(/xxxxx
)で呼ばれる処理- 独自のモジュールを用意し、
app.module.ts
にぶら下げる
- 独自のモジュールを用意し、
NestJS なら必要な機能はぼぼ揃っている
NestJS は、Webアプリ開発なら必要となるであろう機能や処理(例: ログインに使う認証処理など)を、あらかじめ「モジュール」として用意してくれている。
他のフレームワークなら、わざわざネット上からやりたいことを実現できる拡張機能のプログラムを探し、現在のバージョンでも正しく動くかを検証した上で、自分のアプリに追加しなければならないが、
NestJS はフルスタックフレームワークなので、そういった便利機能もほとんどが既に公式として用意されており、「モジュール」として1行追加するだけですぐに利用することができる。
今回説明した基本3概念「モジュール」「コントローラ」「サービス」をベースに様々なモジュールを追加していくと、色んなケースに対応できる、リッチな API アプリケーションになる。