0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【NestJS】ルーティングはデコレータで決まる 〜URLがどう組み立てられるか〜

0
Posted at

概要

NestJSのルーティングは、Expressのように「パスとハンドラ」を書き並べるのではなく、@Controller や @Get といったデコレータで宣言します。

この記事では、main.ts のグローバルプレフィックス → コントローラー → モジュールへの登録という3ステップで、1本のURLがどう組み立てられるかを整理します。

前提:Expressとの比較

まず、生のExpressでルーティングを書くとこうなります。

// Express の場合(パスとハンドラを明示的に結びつける)
app.get('/api/users', (req, res) => { ... });
app.post('/api/users', (req, res) => { ... });
app.get('/api/users/:id', (req, res) => { ... });

「どのURLにどの関数を割り当てるか」を自分で書き並べる方式です。数が増えるとパスの重複や書き漏れに気づきにくくなります。

NestJSはこれをデコレータで宣言的に置き換えます。ルーティングテーブルはフレームワークが起動時に組み立てるので、開発者はクラス・メソッドに「担当するURL」をラベルとして貼るだけになります。


デコレータとは

@〇〇 の記法で、クラスやメソッドにメタ情報(ラベル)を付ける仕組みです。NestJSが起動時にラベルを読み取り、ルーティングテーブルを自動で組み立てます。

デコレータ自体は関数呼び出しなので、@Get(':id') は「:id というパスを覚えておいて」というメタデータを、そのメソッドに紐付けているだけです。それ自体はルーティングを行いません。実際の登録は後述の起動処理で行われます。

ステップ1:グローバルプレフィックス

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

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

  app.setGlobalPrefix('api'); // 全エンドポイントに /api を付ける

  await app.listen(3000);
}
bootstrap();
  • NestFactory.create(AppModule) で、AppModule を起点にアプリ全体を組み立てます
  • setGlobalPrefix('api') で、全URLが /api/... 始まりになります

一部のパスだけプレフィックスから除外する

ヘルスチェックのように /api を付けたくないエンドポイントは exclude で除外できます。

import { RequestMethod } from '@nestjs/common';

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

ステップ2:コントローラーでパスを宣言

// src/users/users.controller.ts
import { Controller, Get, Post, Body, Param, Query } from '@nestjs/common';

@Controller('users') // このクラスは /users を担当
export class UsersController {

  @Get()            // GET /api/users
  findAll(@Query('limit') limit?: string) {
    return [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
  }

  @Get(':id')       // GET /api/users/1
  findOne(@Param('id') id: string) {
    return { id, name: 'Alice' };
  }

  @Post()           // POST /api/users
  create(@Body() body: { name: string }) {
    return { id: 3, name: body.name };
  }
}

※@Controller('users') のパスに先頭スラッシュは不要

URLの組み立て

グローバルプレフィックス  /api
         +
@Controller             /users
         +
@Get(':id')             /:id
         =
GET /api/users/1  →  findOne() が呼ばれる

リクエストから値を取り出すデコレータ

デコレータ 取得元 例
@Param('id') URLパスパラメータ /users/1 → '1'
@Query('limit') クエリ文字列 /users?limit=10 → '10'
@Body() リクエストボディ { "name": "Alice" }
@Headers('authorization') ヘッダー 'Bearer ...'

ステップ3:モジュールにコントローラーを登録

// src/users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';

@Module({
  controllers: [UsersController], // ここに登録して初めて有効になる
})
export class UsersModule {}
// src/app.module.ts
import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module';

@Module({
  imports: [UsersModule], // AppModuleに取り込む
})
export class AppModule {}

デコレータを正しく書いていても、controllers への登録や imports への取り込みを忘れると、そのエンドポイントは存在しません(404が返ります)。

なお、コントローラーが依存するサービスは同じモジュールの providers に登録します(ルーティングの話からは外れるので詳細は割愛)。

@Module({
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}

主なルーティングデコレータ一覧

@Get('path')     // GET     /api/path
@Post('path')    // POST    /api/path
@Put('path')     // PUT     /api/path
@Patch('path')   // PATCH   /api/path
@Delete('path')  // DELETE  /api/path
@Head('path')    // HEAD    /api/path
@Options('path') // OPTIONS /api/path
@All('path')     // 全HTTPメソッドを受ける

@Put は「リソース全体の置き換え」、@Patch は「一部更新」という使い分けが一般的です。

NestJS起動時の流れ

npm run start:dev
  ↓
main.ts が実行される
  ↓
AppModule を読み込む
  ↓
imports に書かれた UsersModule を読み込む
  ↓
controllers に書かれた UsersController のデコレータを読み取る
  ↓
以下のルーティングテーブルを自動登録:
  GET    /api/users      → findAll()
  GET    /api/users/:id  → findOne()
  POST   /api/users      → create()
  ↓
リクエスト待ち状態へ

まとめ

設定箇所 デコレータ/メソッド 役割
main.ts app.setGlobalPrefix('api') 全URLの先頭に /api を付ける
コントローラークラス @Controller('users') クラスのURL担当範囲を決める
コントローラーメソッド @Get() @Post() など HTTPメソッドとパスを紐付ける
コントローラーメソッドの引数 @Param() @Query() @Body() リクエストから値を取り出す
モジュール controllers: [...] コントローラーをNestJSに認識させる
AppModule imports: [...] モジュールをアプリに取り込む

デコレータを読むだけでそのクラス・メソッドがどのURLを担当しているかが一目でわかるのがNestJSの特徴ですね。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?