Chapter1: NestJSを使ってみた 文字列を返すシンプルなAPI実装
Prev Chapter
これはなに
このチャプターでは、以下の2つのAPIを実装します。
- GET
/users
- POST
/users
今回は、実装したルートにアクセスすると文字列が返却されるシンプルなAPIを実装し、各クラスや機能を確認していきます。
今回実装するクラスは以下です。
- UserModule
- UserController
- UserService
githubのリポジトリも公開しているので必要であれば、こちらも参照してみてください。
前Chapterでも記載しましたが、公式ドキュメントのこちらのページの後にすすめてもらえるとスムーズだと思います。
NestJSのModuleについて
NestJSはモジュラアーキテクチャを採用しています。モジュラアーキテクチャとは構成要素ごとにモジュール化した部品を作成し、それらを結合し機能を実装します。モジュールごとに独立して実装を行うので各モジュール同士は疎結合な状態を保つことが出来、実装の柔軟性やテスト容易性を実現できます。
NestJSのアプリは基本的に1つのルートモジュール(AppModule
)を持っており、ルートモジュールに実装した各モジュールimport
させて、アプリの機能を追加していきます。
Moduleの関係サンプル
コードサンプル
import { Module } from '@nestjs/common';
import { UserModule } from './modules/user/user.module';
import { PostModule } from './modules/post/post.module';
import { MessageModule } from './modules/message/message.module';
@Module({
imports: [UserModule, PostModule, MessageModule],
})
export class AppModule {}
実装
ここから実装に入ります。
UserController
NestJSは一般的なフレームワークと違い、ルーティングを別ファイルで定義するのではなくコントローラで定義します。コントローラを見るだけで、どのルーティングからコントローラのメソッドが呼び出されているかが確認できます。NestJSはルーティングとコントローラの分離による煩雑さをこのような手法で解決しています。
import { Controller, Get } from '@nestjs/common';
import { UserService } from './user.service';
@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) {}
@Get()
findAll() {
return this.userService.findAll();
}
@Post()
create(() {
return this.userService.create();
}
}
@Controller()
デコレータでパスのプレフィックスをusers
を設定します。
Controllerの各メソッドに@Get()
, @Post()
デコレータを修飾することで以下のルーティングが設定できます。
パス | メソッド | Controllerメソッド |
---|---|---|
/users |
GET | findAll() |
/users |
POST | create() |
UsersController
に@Get('hogehoge')
で修飾したメソッドを実装すれば、GET /users/hogehoge
ルートを設定することも可能です。
constructor
でUserService
を生成し、各メソッドで利用します。
UserService
UserController
で利用する`UserServiceを実装します。
import { Injectable } from '@nestjs/common';
@Injectable()
export class UserService {
findAll() {
return 'findAll users';
}
create() {
return 'create user';
}
}
NestJSにはDependency Injection(依存注入)というデザインパターンを採用しています。先に実装したUserController
もコンストラクタでUserService
を依存注入します。
NestJSでは注入するクラスを Providerと呼び、@Injectable
デコレータを修飾することで他のクラスに依存注入が出来るようになります。
UserModule
Moduleクラスでは必要な依存関係を整理し、カプセル化を行います。
実装したUserController
はUserService
に依存しています。
@Module()デコレータを利用してUserModule
を実装します。
import { Module } from '@nestjs/common';
import { UserController } from './user.controller';
import { UserService } from './user.service';
@Module({
controllers: [UserController],
providers: [UserService],
})
export class UserModule {}
@Module
デコレータのcontrollers
にUserController
、providers
にUserService
をセットします。
AppModule
UserModule
をルートモジュールであるAppModule
にimportします。
AppController
, AppService
は利用しないので消してしまいます。
import { Module } from '@nestjs/common';
import { UserModule } from './modules/user/user.module';
@Module({
imports: [UserModule],
})
export class AppModule {}
以下のファイルも不要なので削除してしまいます。
- app.controller.spec.ts
- app.controller.ts
- app.service.ts
最終的なディレクトリ構成は以下のようになります。
src
├── app.module.ts
├── main.ts
└── modules
└── user
├── user.controller.spec.ts
├── user.module.ts
├── user.service.spec.ts
├── user.service.ts
└── users.controller.ts
動作確認
実装が終わったので動作の確認します。
$ npm run start:dev
curlでAPIを叩いてみて以下のレスポンスが帰ってきたら成功です。
$ curl http://localhost:3000/users
findAll users%
$ curl -X POST http://localhost:3000/users
create user%
試しにUserModule
のProviderのUserService
を削除し、npm run start:dev
を行ってみると
providers
に必要なクラス(UserService
)がないので、依存関係の解決が出来ずに以下のようなエラーが出ます。
ためしに削除してみるとNestJSのModule
の役割が確認できるかと思います。
Error: Nest can't resolve dependencies of the UserController (?). Please make sure that the argument UserService at index [0] is available in the UserModule context.
おわり
今回修正した内容です。
次のChapterはPrismaのインストール/設定を行ない、マイグレーションを行います。
Discussion