iT邦幫忙

2021 iThome 鐵人賽

DAY 3
0
Modern Web

NestJS 帶你飛!系列 第 3

[NestJS 帶你飛!] DAY03 - Controller (上)

在 Nest 的世界裡,Controller 負責路由的配置並處理來自客戶端的請求,而每一個 Controller 都可以依照需求來設計不同 Http Method 的資源,就好像外場服務生負責帶位、協助客人點餐一樣,並根據客戶的需求做出相對應的回應:
https://ithelp.ithome.com.tw/upload/images/20210303/20119338DiMtfCY7e3.png

總體來說,Controller 就是一個處理客戶端請求,並將相同性質的資源整合在一起的元件。

建置 Controller

所有的 Controller 都必須使用 @Controller 裝飾器來定義。可以用 NestCLI 快速生成 Controller:

$ nest generate controller <CONTROLLER_NAME>

注意<CONTROLLER_NAME> 可以含有路徑,如:features/todo,這樣就會在 src 資料夾下建立該路徑並含有 Controller。

這邊我建立了一個名為 todo 的 Controller:

$ nest generate controller todo

src 底下會看見一個名為 todo 的資料夾,裡面有 todo.controller.ts 以及 todo.controller.spec.ts
https://ithelp.ithome.com.tw/upload/images/20210303/20119338V5DCWGtyKY.png

由於只有建立 Controller,所以會自動將其歸納於根模組下,也就是說 AppModule 會多引入 TodoController

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TodoController } from './todo/todo.controller';

@Module({
  imports: [],
  controllers: [AppController, TodoController],
  providers: [AppService],
})
export class AppModule {}

路由

在建置完 Controller 基本骨架後,會發現 todo.controller.ts@Controller 多了一個字串 todo,這是路由的 前綴 (prefix)

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

@Controller('todo')
export class TodoController {}

注意:透過 NestCLI 建立的 Controller 前綴預設使用該 Controller 的名稱,通常會習慣把名稱取單數,而前綴改為複數。

添加路由前綴的好處是可以使相同路由的資源都歸納在同一個 Controller 裡面,其中包含了前綴底下的所有子路由:
https://ithelp.ithome.com.tw/upload/images/20210304/20119338Y3BtOcUSDt.png

Http Methods

可以透過添加裝飾器在 class 的方法上,來指定不同 Http Method 所呼叫的方法,Nest 會根據 Controller 與指定的 Http Method 裝飾器來建立路由表。以下方程式碼為例,使用的為 GET

import { Controller, Get } from '@nestjs/common';

@Controller('todos')
export class TodoController {
  @Get()
  getAll() {
    return [];
  }
}

使用瀏覽器進入 http://localhost:3000/todos 來查看結果:
https://ithelp.ithome.com.tw/upload/images/20210321/20119338AV8qBUugaH.png

Nest 的 Http Method 裝飾器名稱即對應標準 Http Method,這裡做了些歸納:

  • @Get:表示接收對應路由且為 GET 請求時觸發。
  • @Post:表示接收對應路由且為 POST 請求時觸發。
  • @Put:表示接收對應路由且為 PUT 請求時觸發。
  • @Patch:表示接收對應路由且為 PATCH 請求時觸發。
  • @Delete:表示接收對應路由且為 DELETE 請求時觸發。
  • @Options:表示接收對應路由且為 OPTIONS 請求時觸發。
  • @Head:表示接收對應路由且為 HEAD 請求時觸發。
  • @All:表示接收對應路由且為以上任何方式的請求時觸發。

子路由

在設計路由時,很有可能會有子路由的需求,比如說:/todos 底下還有一個取得範例的資源,定義為 GET /todos/examples,但不可能每次有子路由都建立一個新的 Controller,這時候就可以透過 Http Method 裝飾器指定子路由,會基於 Controller 設置的前綴來建立,以下方程式碼為例,取得資源的路由為 GET /todos/examples

import { Controller, Get } from '@nestjs/common';

@Controller('todos')
export class TodoController {
  @Get('/examples')
  getExample() {
    return [
      {
        id: 1,
        title: 'Example 1',
        description: ''
      }
    ];
  }
}

使用瀏覽器進入 http://localhost:3000/todos/examples 查看結果:
https://ithelp.ithome.com.tw/upload/images/20210321/20119338QJKDhS5rxx.png

通用路由符號

注意:該用法使用上需要謹慎,基本上除了 ? 以外,都是被允許的字元。

有時候設計路由時,可能會提供些許的容錯空間,比如說:原本是 GET /todos/examples,但不管是 /todos/exammmmmmmmples 還是 /todos/exam_ples 都可以得到 /todos/examples 的結果,主要是在指定路由時,使用了 *。下方為範例程式碼:

import { Controller, Get } from '@nestjs/common';

@Controller('todos')
export class TodoController {
  @Get('exam*ples')
  get() {
    return [
      {
        id: 1,
        title: 'Example 1',
        description: ''
      }
    ];
  }
}

使用瀏覽器進入 http://localhost:3000/todos/exammmmmmmmples 查看結果:
https://ithelp.ithome.com.tw/upload/images/20210321/20119338mpLJR0C4Dv.png

路由參數 (Path Parameters)

路由參數的設計十分簡單,會在 Http Method 裝飾器上做定義,字串格式為 :<PARAMETER_NAME>,接著要在該方法中添加帶有 @Param 裝飾器的參數,這樣就可以順利取得路由參數。這裡我們新增一個路由參數為 id 的路由,程式碼如下:

import { Controller, Get, Param } from '@nestjs/common';

@Controller('todos')
export class TodoController {
  @Get(':id')
  get(@Param() params: { id: string }) {
    const { id } = params;
    return {
      id,
      title: `Title ${id}`,
      description: ''
    };
  }
}

這裡還有另一種方式可以取得特定路由參數,就是在 @Param 帶入指定參數名稱:

import { Controller, Get, Param } from '@nestjs/common';

@Controller('todos')
export class TodoController {
  @Get(':id')
  get(@Param('id') id: string) {
    return {
      id,
      title: `Title ${id}`,
      description: ''
    };
  }
}

使用瀏覽器進入 http://localhost:3000/todos/1 查看結果:
https://ithelp.ithome.com.tw/upload/images/20210321/20119338gdLrnUsRRy.png

查詢參數 (Query Parameters)

查詢參數與路由參數取得的方式很相似,但不需要在 Http Method 裝飾器中做任何設置,只需要在方法中添加帶有 @Query 的參數即可。這裡我們做一個簡單的範例:

import { Controller, Get, Query } from '@nestjs/common';

@Controller('todos')
export class TodoController {
  @Get()
  getList(@Query() query: { limit: number, skip: number }) {
    const { limit = 30, skip = 0 } = query;
    const list = [
      {
        id: 1,
        title: 'Title 1',
        description: ''
      },
      {
        id: 2,
        title: 'Title 2',
        description: ''
      }
    ];

    return list.slice(skip, limit);
  }

}

也可以取得特定查詢參數,就是在 @Query 帶入指定參數名稱:

import { Controller, Get, Query } from '@nestjs/common';

@Controller('todos')
export class TodoController {
  @Get()
  getList(
    @Query('limit') limit: number = 30,
    @Query('skip') skip: number = 0
  ) {
    const list = [
      {
        id: 1,
        title: 'Title 1',
        description: ''
      },
      {
        id: 2,
        title: 'Title 2',
        description: ''
      }
    ];

    return list.slice(skip, limit);
  }
}

使用瀏覽器進入 http://localhost:3000/todos?limit=1 查看結果:
https://ithelp.ithome.com.tw/upload/images/20210321/20119338OE2TcjIxkQ.png

狀態碼 (Http Code)

預設情況下,除了 POST 會回傳 201 外,大多數的 Http Method 都是回傳 200,不過應該要以實際情況來回傳適當的狀態碼。Nest 提供了狀態碼的 enum,並用裝飾器來設置回傳的狀態碼,十分貼心!下方為範例程式碼:

import { Controller, Patch, HttpCode, HttpStatus } from '@nestjs/common';

@Controller('todos')
export class TodoController {
  @Patch()
  @HttpCode(HttpStatus.NO_CONTENT)
  get() {
    return [];
  }
}

這裡用 Postman 來查看結果:
https://ithelp.ithome.com.tw/upload/images/20210307/20119338SMhRWZ9bqo.png

小結

今天的內容稍微多了些,這邊幫大家懶人包一下:

  1. Controller 負責路由及處理來自客戶端的請求。
  2. Controller 可以將相同路徑下的資源整合在一起,包含子路由。
  3. 透過 Http Method 裝飾器輕鬆配置對應的資源。
  4. 透過 @Param 取得路由參數、透過 @Query 取得查詢參數。
  5. 透過 @HttpCodeHttpStatus 來配置該資源回傳的狀態碼。

Controller 的功能非常多,如果都放在同一篇的話篇幅會過長,所以剩下的部分會在下一篇繼續說明。


上一篇
[NestJS 帶你飛!] DAY02 - Hello NestJS
下一篇
[NestJS 帶你飛!] DAY04 - Controller (下)
系列文
NestJS 帶你飛!32

尚未有邦友留言

立即登入留言