🧑‍💻

Nestjsを初めて触ってみて学んだこと備忘録

2024/06/06に公開

NestJSを使っているプロジェクトに先日アサインされ、初めてコードを読み始めました。
これまで主にMVC系のフレームワークを使っていたので、慣習の違いに戸惑う日々。
最初にわからなかったこと、わかりづらかったことを書いていこうと思います。

NestJSとは?

・バックエンドのnodejsベースのフレームワーク
・typescriptベースで書くことができる
公式サイト:https://nestjs.com/

まずはルーティング。URLに対して、どのファイルのどのコードを読めばいいのか

あるURLにgetやpostが飛んだ時、どのファイルを読めばいいのか?
いわゆるルーティング。mvcモデルのフレームワークだとルーティング記述がまとめられたファイルがあるんですが、それに当たるものが見当たらない。。
ここにまずハマりました。

結論(に近いこと)から言うと、NestJSにおいては
@Controller()や@Get()、@Post()、@Putなどを見つければそれがルーティングのヒントになります。
基本的には コントローラー + @Get()、@Post()、@Put()などのメソッドがそのURLになります。

例えば URLが/Fuga/ のgetリクエストの場合。。。
以下のように、@Controller('Fuga')の中の@Get()。
この中でやっている処理(console.log)が、このURLにgetアクセスした時に行う処理、ということになります。

@Controller('Fuga')
export class FugaController{
  @Get()
  async test{
    console.log('/Fugaの処理');
  }
}

@Get()に引数を入れれば、URLを追加できます。

◼️ /Huge/items/list/へのgetリクエスト

@Controller('Huge')
export class HogeController{
  @Get('items/list')
  async test{
    console.log('/Huge/items/listの処理');
  }
}

postの場合も考え方は同じ。

◼️ /Huge/items/list/へのpostリクエスト

@Controller('Huge')
export class HugeController{
  @Post('items/list')
  async test{
    console.log('/Huge/items/listの処理');
  }
}

数字などがurlに入る場合。

◼️/Company/10/へのGetリクエスト

@Controller('Company')
export class CompanyController{
  @Get(':id')
  async test{
    console.log('/Company/10/の処理');
  }
}

わかりづらいケース。

◼️/team/10/setting/へのGetリクエスト

この場合、今までのルールで考えると想定としては
@Controller('team')
@Get(':id/setting')
が使われているかなと考えていたんですが、以下のようになっていました。

@Controller('team/:id/setting')
export class TeamController{
  @Get()
  async test{
    console.log('/team/10/setting/の処理');
  }
}

@Controller()の中でほとんどのルーティングをまかなっています。
つまり、ルーティングを調べても見つからない場合は

「コントローラーの中に、または@Getや@Postなどにバランス悪く分けられていないか?」

という思考で探すと良いかと思います。

ちなみにデコレーターって何?

上のルーティングにも記載されている@Controller('Huge')とは一体?

簡単にいうと、このような書き方をすると対象に対してなんらかのロジック処理を追加できる仕組みです。クラス、メソッド、プロパティ、引数などに適用することができます。

@hoge
対象

基本のファイル(エントリーファイル)はどこ?

そもそもアプリ起動時、どこからアプリが始まっているのか?

src/main.ts

でした。
この中のasync function bootstrapでアプリを起動しています。

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();

エントリーファイル(基準となるファイル)の変更はどこでできる?

「nest-cli.json」で行えます。デフォルトは以下の状態。

{
  "$schema": "https://json.schemastore.org/nest-cli",
  "collection": "@nestjs/schematics",
  "sourceRoot": "src",
  "compilerOptions": {
    "deleteOutDir": true
  }
}

sourceRootで指定した「src」の中の「main.ts」がエントリーファイルにあたります。

ちなみに、main.tsではなく他のファイルをエントリーファイルにしたい場合は「entryFile」を指定すると良い。
例えばこう書くと、、、

{
  "$schema": "https://json.schemastore.org/nest-cli",
  "collection": "@nestjs/schematics",
  "sourceRoot": "src2", //ここと
  "entryFile": "app", //ここが肝!
  "compilerOptions": {
    "deleteOutDir": true
  }
}

これらの記述の場合、src2/app.tsがエントリーファイルになります。

CORS設定について(フロントエンドからのapiアクセスを許可する、しない)

前述のbootstrapの中で下記の設定をする。

  app.enableCors({
    origin: 'http://localhost:3001',//許可するURL。なんでも許可するなら'*'とする
    methods: 'GET,PUT,POST,DELETE',//許可するメソッド
    allowedHeaders: [
      'Content-Type',
      'csrf-token',
      'xsrf-token',
      'x-csrf-token',
      'x-xsrf-token',
    ],
    credentials: true,
  });

credentialsなどのオプションは以下を参考できるようです。
https://github.com/expressjs/cors#configuration-options

APIのエンドポイントURLにプレフィックスをつけたい

NestJSで返す値は基本的にはapiなので、下記のように記述(やはりbootstrapの中に記述)することで、基本的なURLを編集することができます。

app.setGlobalPrefix('api/v1', {
    exclude: [{ path: 'healthcheck', method: RequestMethod.GET }],
    });

例えば上記のように記述すると、例えば元のURLが「/users/」であれば、
「/api/v1/users」にアクセスした際に作動する。ということになります。
apiのバージョンを変更するときなどに変更する、というものになるかと思います。

また、excludeは文字通り除外する値で、上記の記載だと
healthcheckにGETでのアクセスをした際にはこのルールは適用されない・・・
つまりシンプルに「/healthcheck/」でアクセスできるということになります。

参考:https://docs.nestjs.com/faq/global-prefix

Discussion