2022/03/08
はじめに
NestJS とは,Node.js のバックエンドフレームワークである.以下,公式ドキュメントを参考に紹介.
NestJS は効率的でスケーラブルな Node.js のサーバサイドアプリケーションを開発するためのフレームワークとされている.また,TypeScript を完全にサポートしており,OOP/FP/FRP の要素を組み合わせている.
また NestJS では,好みによって Node.js 製 Web フレームワークである Express/Fastify を使い分けることが可能.
NestJS の生まれた背景としては,Node.js のおかげで JS がフロントエンド・バックエンドの共通言語となった事が挙げられ,これにより様々な SPA ライブラリ・フレームワークが発展した一方で,バックエンドに対しても便利なライブラリやツールは存在するものの,主にアーキテクチャの効率性は改善されていないとされている.
そこで NestJS はフレームワーク自体が開発者にテスタビリティ・スケーラビリティ・疎結合・メンテナビリティを提供できるように設計されている.また,NestJS は Angular に多くの影響を受けている.
使い方
インストール
npm
を用いて CLI ツールをグローバルインストールする.
$ npm i -g @nestjs/cli
プロジェクトの作成
CLI を用いるとコマンド一発でプロジェクトをセットアップ可能.
$ nest new my-project
ここで,使いたいパッケージマネージャを選択する.(僕は npm)
生成されたファイル
CLI によって,eslint/prettier/tsconfig 等の設定ファイルは自動的に生成される.
実際に開発を進める上では,src
をいじっていく.
main.ts
には NestJS におけるおまじないが書かれている.ポートの変更や cookie-parser 等を用いたい場合はここに追記する.Express におけるapp.use(...)
の記述はこのファイルに書く.
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// app.user(...)が追記可能
// ポート3000を利用する
await app.listen(3000);
}
bootstrap();
main.ts
以外のファイルは<name>.<schematic>.ts
のような命名規則で保存するようになっている.
app.module.ts
:アプリケーション全体のモジュール.モジュールを追加する場合,ここに追加することで,モジュールをアプリケーションに設定できる.app.controller.ts
: REST API のエンドポイントapp.service.ts
:REST API の処理部
Front からのアクセスの流れは,app.controller
→ app.service
の流れである.
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
// AppModuleで利用する他のModuleをセット
imports: [],
// AppModuleで利用するControllerをセット
controllers: [AppController],
// AppModuleで利用するProviderをセット
providers: [AppService],
// 外部から利用させる処理をセット
// exports: []
})
export class AppModule {}
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
// AppModuleのprovidersにセットされたServiceがInjectされており,constructorで受け取る
// appServiceはAppServiceのインスタンスとして使うことが出来る
constructor(private readonly appService: AppService) {}
// `localhost:3000/` に対するGETメソッドを割り当てる
// @Get('hello')とすると `localhost:3000/hello` に割り当てる
// 他のメソッドには@Post/@Put/@Deleteのように別で割当可能
@Get()
getHello(): string {
// AppService.getHello()の結果をレスポンスとして返す
return this.appService.getHello();
}
}
import { Injectable } from '@nestjs/common';
// Inject可能なクラスをつくる
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}
ここで,app.controller.ts
,app.service.ts
に関してはサンプルプロジェクトには含まれているものの,これらは実際にアプリケーションを開発する上では,多くの場合は削除することをおすすめする.(次項につづく)
モジュールの追加
実際のアプリケーションにおいてはuser
やtodo
のように用途ごとにエンドポイントを設定したい場合が多いと思う.その際にapp.controller.ts
のような命名で運用すると,粗結合にならない.
そこで,src/user/user.module.ts
, src/user/user.controller.ts
, src/todo/todo.module.ts
のようなディレクトリ構成にすると,用途ごとに処理を分離することが可能である.
今回は長くなってしまうので省くが,今後別の記事で書いて行ければと思っている.
当初気になった点
利用当初に気になりながら学習を進めた疑問点に対し,ある程度の知識をつけた"今の"自分なりのこたえを残しておく.
Angular 使いじゃないと恩恵が薄いの?
私は以前 Angular をちょびっと触ったことが合ったが,TS 自体は全体を通して React 中心に関わっており,Next.js 辺りを扱っていた.
公式ドキュメントを少し見たところ,「Angular にめっちゃ似てるじゃん!」と思ったし,フレームワークの Module の書き方等で酷似している点も多々ある.
しかし,それは「Angular が得意な人じゃないとかけない」というわけではなく,「Angular と同じような書き方でバックエンドを書く」という印象がある.
React での開発と NestJS との開発を並行しても特段頭の切り替えが必要になることはない.
Express とどっちがいいの?
バックエンドで Node.js を使うことを決めた上で Express/NestJS で迷った.
選定基準における注意点だが,選定中の自分は,とても間抜けでnpm trends
で Express/NestJS の比較などを行っていた.NestJS の内部では Express/Fastify が使われているためこれは全く意味がなく,NestJS が伸びれば自然と Express も伸びるので比較対象としては正しくない.これを比較するのは,react/next.js の DL 数を比較するようなものである.
Express は書き方が多数存在するようで,構成や設計に対し先人の知恵を活かしたければそれだけ動向を調べる必要があるように感じた.そのため,初期段階から設計にある程度の縛りがあり,公式ドキュメントおよびパッケージが充実している NestJS を選んだ.
また,NestJS の推しポイントである粗結合というのが,動作速度のボトルネックを切り分けて別言語にできるのではという淡い期待から,他言語への部分的な移行を考え,NestJS に魅力を感じた.
Next.js の API Route でいいんじゃない?
React→Next.js の順に学んでみると,なんともスムーズに フロントエンド開発からバックエンドへの接続ができる.Next.js の SSR/SSG/ISR は素晴らしいし,API Route(ディレクトリベースの API)も手軽で素晴らしい.
一応断っておくが,私は Next.js は愛用しているが,API Route は入門程度でほとんど使ったことがないため,公平ではないかもしれない
思うに,「AWS Lambda を JSON サーバとして運用するぞ!」と言ったモチベーションの場合は NestJS を使うよりも API Route を使ったほうが学習効率・デプロイの簡易性・CICD の容易な構築と,多くの恩恵を Vercel から受けられることは間違いない.そして,API Middleware などでどんどん拡張性が向上しているように見える.
しかし,複雑な機能を持つバックエンドを構築したいのであれば,NestJS の方がそちらに重点を置いており,フレームワークとしてのサポートが豊富である.
これに関しては,やりたい事や用途,開発体制で検討する余地があるだろう.
Go とか使わないの?
NestJS がいいなと思った直前,Golang を触っていたため,自分の中でそこは本当に迷ったところであった.また,最近存在感がましてきている Rust にも惹かれていた(Rust はその後軽く学習した).
ここは考え方の違いとなるだろうが,「開発時に発生する頭の切り替えを可能な限り減らす」という事を重視したため NestJS(Node.js)を選んだ.
これに関しては開発に関わる人数や体制が影響すると思う.個人開発等で全て自分が関わる必要がある場合は,Front/Back 両方に関わるため,両者を行き来する上での頭の切り替えが発生することが,開発の進行上,および精神衛生上良くないと感じた.
仮に開発にかかる人数が多くて Front/Back を専任のエンジニアが携わる場合は,より高速な言語を選定するのも良い選択だと思うし,部分的に高速化を果たすために Golang や Rust 等を選ぶのも良い選択だと思う.
おわりに
NestJS いいですねぁ!