iT邦幫忙

2023 iThome 鐵人賽

0
自我挑戰組

用ChatGPT詠唱來完成工作與點亮前後端技能樹系列 第 43

【Day43】ChatGPT請教教我:NestJS!(二)- Controller & 裝飾器

  • 分享至 

  • xImage
  •  

上一篇我們學了基本的NestJS語法
接下來要個別的詳細&深入了解更多語法與用法

本篇要討論的是Controller !

基本Controller教學

https://ithelp.ithome.com.tw/upload/images/20231026/20135750rd73xZ7ki1.png

當然可以!現在我會以詳細且易於跟著操作的方式,用繁體中文來教你有關 NestJS 的 controller。

首先,讓我們確保你已經在你的專案中安裝了 NestJS。如果還沒有的話,可以在終端機中執行以下指令:

npm install -g @nestjs/cli
nest new project-name

接下來,我們會建立一個 controller。Controller 負責接收來自客戶端的請求並處理它們。首先,在終端機中執行以下指令:

nest generate controller cats

這個指令將會創建一個名為 cats.controller.ts 的檔案在 src/cats 目錄下,並且也會創建一個測試檔案。

現在,打開 cats.controller.ts 檔案,你會看到類似以下的程式碼:

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

@Controller('cats')
export class CatsController {
  @Get()
  findAll(): string {
    return 'This action returns all cats';
  }
}

這個 controller 包含了一個路由 cats 以及一個 GET 請求的處理器。當使用者在瀏覽器中輸入 http://localhost:3000/cats 時,將會呼叫 findAll 方法並返回一個字串。

接著,你可以在這個方法中處理相應的邏輯,比如從資料庫中取得資料或者進行其他運算。

最後,別忘了在模組中引入這個 controller。打開 app.module.ts 檔案,確保你的 CatsController 被加入到模組的 controllers 中:

import { Module } from '@nestjs/common';
import { CatsController } from './cats/cats.controller';

@Module({
  controllers: [CatsController],
})
export class AppModule {}

這樣你的 NestJS 專案就有了一個簡單的 controller。你可以根據需要,添加更多路由和處理器來擴充功能。

希望這個教學對你有所幫助!如果有任何問題,請隨時問我。

因為是請ChatGPT單獨介紹controller,所以ChatGPT沒有將controller 連結到其他的module
而是放到根Module中 (app.module.ts)
也沒有特別使用service ,直接將內容return回傳

上面的基礎用法在上一篇已經提過了,我們要探討更近一步的介紹
https://ithelp.ithome.com.tw/upload/images/20231026/20135750ZSNGB9QthS.png

當然,讓我更進一步地介紹 NestJS 的 controller。

在 NestJS 中,Controller 負責處理來自客戶端的請求,並且根據請求的類型(GET、POST、PUT、DELETE 等)調用相應的方法。

添加路由和請求方法

現在讓我們繼續在 cats.controller.ts 中添加更多路由和相應的請求方法。

import { Controller, Get, Post, Put, Delete, Param, Body } from '@nestjs/common';

@Controller('cats')
export class CatsController {
  @Get()
  findAll(): string {
    return 'This action returns all cats';
  }

  @Get(':id')
  findOne(@Param('id') id: string): string {
    return `This action returns a cat with ID ${id}`;
  }

  @Post()
  create(@Body() createCatDto: any): string {
    return `This action creates a new cat with the following data: ${JSON.stringify(createCatDto)}`;
  }

  @Put(':id')
  update(@Param('id') id: string, @Body() updateCatDto: any): string {
    return `This action updates a cat with ID ${id} with the following data: ${JSON.stringify(updateCatDto)}`;
  }

  @Delete(':id')
  remove(@Param('id') id: string): string {
    return `This action removes a cat with ID ${id}`;
  }
}

這裡我們新增了四個方法,分別對應了不同的請求類型:

  • findAll(): 處理 GET 請求,返回所有的貓咪資訊。
  • findOne(@Param('id') id: string): 處理 GET 請求,返回特定 ID 的貓咪資訊。
  • create(@Body() createCatDto: any): 處理 POST 請求,用於創建新的貓咪資訊。
  • update(@Param('id') id: string, @Body() updateCatDto: any): 處理 PUT 請求,用於更新特定 ID 的貓咪資訊。
  • remove(@Param('id') id: string): 處理 DELETE 請求,用於刪除特定 ID 的貓咪資訊。

路由參數和請求主體

你可能注意到了 @Param@Body 裝飾器。這些裝飾器允許我們從請求中獲取路由參數和請求主體的資訊。

  • @Param('id') id: string: 這個裝飾器用於獲取路由中的 id 參數,並將其傳遞給相應的方法。
  • @Body() createCatDto: any: 這個裝飾器用於獲取請求的主體資料,通常是一個包含了貓咪相關資訊的物件。

路由前綴

在這個例子中,我們在 @Controller 裝飾器中傳入了 cats,這意味著這個 controller 下的所有路由都會以 /cats 為前綴。

測試你的 Controller

現在你可以啟動你的 NestJS 專案,並使用工具如 Postman 或瀏覽器來測試你的 controller。

簡單地在瀏覽器中輸入 http://localhost:3000/cats 或者使用 Postman 來發送不同類型的請求,觀察 controller 的反應。

這就是 NestJS 中 Controller 的基本用法。當然,你可以根據你的需求進一步擴展和定制你的 controller。

希望這能幫到你!如果有任何問題,請隨時問我。

通常來說Controller的角色,處理的就是「請求」,處理有關接收請求,來呼叫正確的service
所以路由是由Controller 來處理真的是相當合理
就好像express的 app.get('/') ,可以控制路由、請求對應的function

觀察上面的範例,可以發現ChatGPT使用「裝飾器」來處理路由
@Get() 是裝飾器、@Controller 是裝飾器、@Param@Body()也是裝飾器

繼續請ChatGPT提供有關NestJS路由以及裝飾器的介紹

路由 & 裝飾器

https://ithelp.ithome.com.tw/upload/images/20231026/20135750b8I6jv6VDP.png

當然,讓我更詳細地解釋 NestJS 中的裝飾器(decorators)以及路由設定。

裝飾器(Decorators)

在 NestJS 中,裝飾器是一種特殊的 TypeScript 語法,它可以用來為類、方法、屬性等提供額外的資訊,比如元資料(metadata)或者功能擴展。這使得我們可以在不改變原始類的情況下,對其進行擴充。

@Controller()

@Controller() 是一個用來定義控制器的裝飾器。它接受一個字串參數,表示控制器的路由前綴。

@Controller('cats')
export class CatsController {
  // ...
}

在這個例子中,CatsController 被標記為一個控制器,並且所有的路由都會以 /cats 為前綴。

@Get(), @Post(), @Put(), @Delete()

這些裝飾器用來定義特定 HTTP 請求類型的路由處理器。它們可以被標記在方法上,以指示當收到相應類型的請求時,應該調用這個方法。

@Get()
findAll(): string {
  return 'This action returns all cats';
}

在這個例子中,findAll 方法將會處理所有的 GET 請求,並返回一個字串。

@Param(), @Body(), @Query(), @Headers()

這些裝飾器用來獲取請求中的參數、主體、查詢字串或者標頭資訊。

@Get(':id')
findOne(@Param('id') id: string): string {
  return `This action returns a cat with ID ${id}`;
}

在這個例子中,@Param('id') 表示我們想要從路由中獲取 id 參數,並將其傳遞給 findOne 方法。

路由設定

路由設定用來定義如何處理特定類型和路徑的請求。

動態路由參數

動態路由參數允許我們在路由中接受變數,例如:

@Get(':id')
findOne(@Param('id') id: string): string {
  return `This action returns a cat with ID ${id}`;
}

在這個例子中,:id 是一個動態參數,它可以是任何字串,並且會被傳遞給 findOne 方法。

路由前綴

路由前綴是在控制器層級定義的,它會影響到控制器下所有路由的路徑:

@Controller('cats')
export class CatsController {
  // ...
}

所有在這個控制器下的路由都會以 /cats 為前綴。

教學總結

  1. 使用 @Controller() 裝飾器定義控制器,並設定路由前綴。
  2. 使用 @Get(), @Post(), @Put(), @Delete() 等裝飾器定義路由處理器,並指定相應的 HTTP 請求類型。
  3. 使用 @Param(), @Body(), @Query(), @Headers() 等裝飾器獲取請求中的參數、主體、查詢字串或者標頭資訊。
  4. 可以使用動態路由參數來處理可變的路徑。
  5. 路由前綴可以在控制器層級定義,影響該控制器下所有路由的路徑。

希望這能幫助你更好地理解 NestJS 中的裝飾器和路由設定!如果還有任何問題,請隨時詢問。

所以@Controller('cat') 可以控制整個Controller下在「/cats」路由上
讓這個分類的function都可以有相同的前綴
然後每個api用對應的裝飾器定義請求Method&子路由、用對應的裝飾器處理參數
可以像是 cat/1 這樣指定id (動態路由參數)

但我們有時候可能需要 /cats/add 之類的路徑,要怎麼控制這樣的子路由呢?
https://ithelp.ithome.com.tw/upload/images/20231026/20135750b6u7vHji5T.png

在 NestJS 中,你可以在 Controller 下設定子路由。這可以通過將另一個 Controller 嵌套在父 Controller 中來實現。

讓我們以一個實際的例子來說明如何做:

假設你的應用程序有一個 cats 控制器,而每隻貓也可以有一個子控制器來處理特定的功能,例如 feedplay

首先,在 cats 控制器中,我們會建立一個子路由 feedplay

// cats.controller.ts

@Controller('cats')
export class CatsController {
  @Get()
  findAll(): string {
    return 'This action returns all cats';
  }

  @Get(':id')
  findOne(@Param('id') id: string): string {
    return `This action returns a cat with ID ${id}`;
  }

  @Controller('feed') // 子路由
  @Get()
  feedCat(): string {
    return 'You fed the cat!';
  }

  @Controller('play') // 子路由
  @Get()
  playWithCat(): string {
    return 'You played with the cat!';
  }
}

在上述範例中,我們在 CatsController 中定義了兩個子路由,分別是 feedplay

這意味著你現在可以使用以下路徑來訪問這兩個功能:

  • http://localhost:3000/cats/feed 將會呼叫 feedCat 方法
  • http://localhost:3000/cats/play 將會呼叫 playWithCat 方法

這樣,你可以在 NestJS 中輕鬆地設定子路由。希望這能對你有所幫助!如果有任何問題,請隨時詢問。

請求方法

接下來,上面ChatGPT教學統整了 @Get(), @Post(), @Put(), @Delete() 這四種方法
可以對應到HTTP的各種請求方式

有關請求方式的差異,也可以參閱這篇
【Day37】ChatGPT請教教我:NodeJS!Express!RESTful API !
有提到有關API設計的時候,去設計對應的請求方式

那除了GET、POST、PUT、DELETE之外,NestJS還有提供什麼裝飾器呢
https://ithelp.ithome.com.tw/upload/images/20231026/20135750bDrChjc0WT.png

除了 @Get(), @Post(), @Put(), @Delete(),在 NestJS 中還有其他請求方法的裝飾器:

  1. @Patch(): 用於處理 PATCH 請求,通常用於部分更新資源。
@Patch(':id')
update(@Param('id') id: string, @Body() updateCatDto: any): string {
  return `This action updates a cat with ID ${id} with the following data: ${JSON.stringify(updateCatDto)}`;
}
  1. @Options(): 用於處理 OPTIONS 請求,通常用於獲取伺服器支援的請求方法。
@Options()
getOptions(): string {
  return 'This action returns available options';
}
  1. @Head(): 用於處理 HEAD 請求,通常用於獲取資源的標頭資訊。
@Head(':id')
getHeaders(@Param('id') id: string): string {
  return `This action returns headers for cat with ID ${id}`;
}
  1. @All(): 用於處理所有類型的請求(GET、POST、PUT、DELETE 等)。
@All(':id')
handleAll(@Param('id') id: string): string {
  return `This action handles all requests for cat with ID ${id}`;
}

這些裝飾器與相應的 HTTP 請求類型相對應,可以幫助你定義不同類型的路由處理器。

希望這可以幫到你!如果還有其他問題,請隨時詢問。

好的,那麼請求相關的裝飾器都講完了
再來討論和參數獲取相關的 @Param(), @Body(), @Query(), @Headers() 這四個裝飾器
分別來討論這幾個的使用方法

@Param()

https://ithelp.ithome.com.tw/upload/images/20231026/20135750tuqhtWsM1D.png

當然,讓我提供更詳細的 @Param() 裝飾器的教學。

在 NestJS 中,@Param() 裝飾器用於獲取路由中的動態參數(路由參數)。

使用 @Param()

假設我們有一個控制器 CatsController 並且要處理像 /cats/1 這樣的請求,其中的 1 是動態參數,代表貓的 ID。

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

@Controller('cats')
export class CatsController {
  @Get(':id')
  findOne(@Param('id') id: string): string {
    return `This action returns a cat with ID ${id}`;
  }
}

在這個例子中,我們使用了 @Param('id'),這表示我們想要從路由中獲取一個名為 id 的參數,並將其傳遞給 findOne 方法。

示例

現在,當你發送一個 GET 請求到 /cats/1,NestJS 將會自動解析 URL 中的 id 參數並將其傳遞給 findOne 方法。

GET /cats/1

結果:

This action returns a cat with ID 1

這樣你就可以在控制器中使用這個參數進行相應的邏輯處理。

多個動態參數

如果你的路由中有多個動態參數,可以在 @Param() 中使用多個參數:

@Get(':category/:id')
findCat(@Param('category') category: string, @Param('id') id: string): string {
  return `This action returns a ${category} cat with ID ${id}`;
}

在這個例子中,我們獲取了兩個動態參數,分別是 categoryid

選用參數

如果你的動態參數是可選的,你可以在 @Param() 中使用 @Param('id', ParseIntPipe) 來指定一個轉換器,例如 ParseIntPipe 用於將參數轉換為整數。

@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number): string {
  return `This action returns a cat with ID ${id}`;
}

這樣,如果用戶傳遞的 id 不是一個有效的整數,NestJS 將會返回一個 400 錯誤。

希望這個教學能幫到你了!如果還有其他問題,請隨時詢問。

@Body()

https://ithelp.ithome.com.tw/upload/images/20231026/20135750m5HrT9hrGW.png

當然,讓我提供更詳細的 @Body() 裝飾器的教學。

在 NestJS 中,@Body() 裝飾器用於獲取請求的主體資料(request body)。

使用 @Body()

假設我們有一個控制器 CatsController,我們希望在 POST 請求中傳遞一個貓的資訊作為主體資料。

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

@Controller('cats')
export class CatsController {
  @Post()
  create(@Body() createCatDto: any): string {
    return `This action creates a new cat with the following data: ${JSON.stringify(createCatDto)}`;
  }
}

在這個例子中,我們使用了 @Body() 裝飾器,這表示我們想要從請求的主體中獲取資料,並將其傳遞給 create 方法。

示例

現在,當你發送一個 POST 請求到 /cats,並且在主體中傳遞了以下資料:

{
  "name": "Fluffy",
  "age": 3,
  "breed": "Persian"
}

NestJS 將會自動解析主體資料並將其傳遞給 create 方法。

結果:

This action creates a new cat with the following data: {"name":"Fluffy","age":3,"breed":"Persian"}

這樣你就可以在控制器中使用這些資料進行相應的邏輯處理。

使用 DTO(資料傳輸物件)

通常情況下,我們會使用 DTO 來明確指定主體資料的結構,以便於驗證和處理。

export class CreateCatDto {
  readonly name: string;
  readonly age: number;
  readonly breed: string;
}

然後在控制器中使用這個 DTO:

@Post()
create(@Body() createCatDto: CreateCatDto): string {
  return `This action creates a new cat with the following data: ${JSON.stringify(createCatDto)}`;
}

這樣你就可以確保主體資料符合預期的結構。

希望這個教學能幫到你了!如果還有其他問題,請隨時詢問。

這邊提到了一個新的名詞:DTO
看起來就像是TypeScript中標註type的東西
我們針對DTO進行更近一步的詢問
https://ithelp.ithome.com.tw/upload/images/20231026/20135750dEYtUJ080h.png

DTO 是 "資料傳輸物件"(Data Transfer Object)的縮寫。它是一種用於在程式模組之間傳輸資料的設計模式。

在軟體開發中,當不同部分的程式需要交換資料時,通常會使用 DTO。這有助於降低模組之間的耦合度,使得程式的各個部分可以獨立開發、測試和維護。

DTO 通常是一個普通的 TypeScript 或者 JavaScript 物件,其中包含了特定操作所需的資料。它只包含資料,而不包含任何業務邏輯。

舉例來說,在一個網頁應用程式中,當你需要在前端和後端之間傳遞資料時,可以使用 DTO 來明確定義所需的資料結構。

// 一個簡單的 CreateCatDto 的例子
export class CreateCatDto {
  readonly name: string;
  readonly age: number;
  readonly breed: string;
}

在這個例子中,CreateCatDto 是一個用於傳遞創建貓的資料的 DTO。它定義了名字、年齡和品種這三個屬性。

使用 DTO 有幾個好處:

  1. 明確資料結構:DTO 使得資料的結構清晰明確,讓開發者容易理解。
  2. 降低耦合度:DTO 允許不同模組之間傳遞資料,而不需要了解彼此的內部實現。
  3. 提高測試性:可以獨立地測試 DTO,而不需要關心其它部分的邏輯。

總的來說,DTO 是一種很有用的模式,可以幫助管理和傳遞資料在程式中的流動。

這邊先記得DTO是用class來定義的,後面我們再探討為什麼不是用interface,而是用class定義

@Query()

https://ithelp.ithome.com.tw/upload/images/20231026/20135750gQG0rF2Zfr.png

當然,讓我提供更詳細的 @Query() 裝飾器的教學。

在 NestJS 中,@Query() 裝飾器用於獲取 URL 查詢字串(query string)中的參數。

使用 @Query()

假設我們有一個控制器 CatsController,我們希望獲取 URL 查詢字串中的參數,例如 /cats?age=3&breed=Persian

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

@Controller('cats')
export class CatsController {
  @Get()
  findCats(@Query('age') age: string, @Query('breed') breed: string): string {
    return `This action returns cats with age ${age} and breed ${breed}`;
  }
}

在這個例子中,我們使用了 @Query('age')@Query('breed'),這表示我們想要從 URL 查詢字串中獲取 agebreed 參數,並將它們傳遞給 findCats 方法。

示例

現在,當你發送一個 GET 請求到 /cats?age=3&breed=Persian,NestJS 將會自動解析查詢字串參數並將它們傳遞給 findCats 方法。

GET /cats?age=3&breed=Persian

結果:

This action returns cats with age 3 and breed Persian

這樣你就可以在控制器中使用這些查詢字串參數進行相應的邏輯處理。

使用 DTO(資料傳輸物件)

同樣,你也可以使用 DTO 來組織和驗證查詢字串參數。首先,你可以創建一個 DTO,例如 FindCatsDto

export class FindCatsDto {
  readonly age: string;
  readonly breed: string;
}

然後在控制器中使用這個 DTO:

@Get()
findCats(@Query() query: FindCatsDto): string {
  return `This action returns cats with age ${query.age} and breed ${query.breed}`;
}

這樣你就可以確保查詢字串參數符合預期的結構。

希望這個教學幫助你更好地理解如何使用 @Query() 裝飾器來獲取查詢字串參數。如果還有其他問題,請隨時詢問。

@Headers()

https://ithelp.ithome.com.tw/upload/images/20231026/20135750fbrxpSa3K6.png

當然,讓我提供更詳細的 @Headers() 裝飾器的教學。

在 NestJS 中,@Headers() 裝飾器用於獲取請求中的標頭資訊。

使用 @Headers()

假設我們有一個控制器 CatsController,我們希望獲取請求的標頭資訊,例如 Authorization 標頭。

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

@Controller('cats')
export class CatsController {
  @Get()
  findAuthorization(@Headers('authorization') authorization: string): string {
    return `This action received Authorization header: ${authorization}`;
  }
}

在這個例子中,我們使用了 @Headers('authorization'),這表示我們想要從請求的標頭中獲取 authorization 標頭資訊,並將其傳遞給 findAuthorization 方法。

示例

現在,當你發送一個 GET 請求並在標頭中包含 Authorization: Bearer your_token_here 時,NestJS 將會自動解析標頭資訊並將其傳遞給 findAuthorization 方法。

GET /cats
Headers:
  Authorization: Bearer your_token_here

結果:

This action received Authorization header: Bearer your_token_here

這樣你就可以在控制器中使用這個標頭資訊進行相應的邏輯處理。

使用 DTO(資料傳輸物件)

同樣,你也可以使用 DTO 來組織和驗證標頭資訊。首先,你可以創建一個 DTO,例如 AuthorizationDto

export class AuthorizationDto {
  readonly authorization: string;
}

然後在控制器中使用這個 DTO:

@Get()
findAuthorization(@Headers() headers: AuthorizationDto): string {
  return `This action received Authorization header: ${headers.authorization}`;
}

這樣你就可以確保標頭資訊符合預期的結構。

希望這個教學幫助你更好地理解如何使用 @Headers() 裝飾器來獲取請求中的標頭資訊。如果還有其他問題,請隨時詢問。

好耶問過一次DTO,後面的範例整個都加入DTO
另外Header裡面可以取得的東西也應該蠻多的,來問問有沒有其他內容!
https://ithelp.ithome.com.tw/upload/images/20231026/20135750fPkHBrE3o7.png

常見可用的 HTTP 標頭如下:

  1. Accept: 指定客戶端可以接受的回應的媒體類型。
  2. Content-Type: 指定請求或回應的內容類型,通常用於 POST、PUT 等請求中。
  3. Authorization: 包含用於認證的凭證,常見的使用方式是 Bearer Token。
  4. User-Agent: 包含發送請求的用戶代理的資訊,可以用於識別用戶端的類型。
  5. Referer: 包含了該請求是從哪個網頁來的,通常在跟蹤頁面流量時使用。
  6. Cookie: 包含了在之前的請求中由伺服器發送的 cookie。
  7. Origin: 指定了發起請求的來源,用於跨來源資源共享(CORS)。
  8. Host: 指定了目標伺服器的主機名和端口號。
  9. Cache-Control: 指定了請求/回應響應的快取機制。
  10. Content-Length: 指定了請求/回應主體的長度。
  11. Content-Encoding: 指定了回應主體的壓縮方式。
  12. Accept-Encoding: 指定了客戶端可以接受的內容壓縮方式。
  13. ETag: 包含了實體的標籤,用於標識實體並支持快取機制。

這只是一部分常見的 HTTP 標頭,實際上還有許多其他標頭,每個都有其特定的用途和意義。根據需要,你可以在請求或回應中使用這些標頭來達到特定的目的。

其他參數裝飾器

我們問過了他所提供的四種和參數、查詢有關的裝飾器之後
來看看還有沒有其他與參數有關的裝飾器
https://ithelp.ithome.com.tw/upload/images/20231026/20135750SLsY3xlXHa.png

除了 @Param(), @Body(), @Query(), @Headers(),NestJS 還提供了一些其他常用的參數裝飾器,讓你可以更靈活地處理請求。

@Req()

@Req() 裝飾器用於獲取 Express 的 Request 物件,可以使用它來訪問所有請求相關的資訊,如請求頭、請求主體等。

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

@Controller('cats')
export class CatsController {
  @Get()
  findCats(@Req() request: Request): string {
    return `This action received request with URL: ${request.url}`;
  }
}

@Res()

@Res() 裝飾器用於獲取 Express 的 Response 物件,可以使用它來設置回應相關的資訊,如狀態碼、標頭等。

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

@Controller('cats')
export class CatsController {
  @Get()
  findCats(@Res() response: Response): void {
    response.status(200).send('This is the response');
  }
}

@Session() 和 @SessionID()

@Session()@SessionID() 用於獲取 Express 的 Session 物件和 Session ID。

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

@Controller('cats')
export class CatsController {
  @Get()
  findCats(@Session() session: any, @SessionID() sessionId: string): string {
    return `Session ID: ${sessionId}, User: ${session.user}`;
  }
}

這些裝飾器用於處理使用了 Session 的應用程式。

@UploadedFile() 和 @UploadedFiles()

這兩個裝飾器用於處理上傳的檔案。

import { Controller, Post, UploadedFile, UploadedFiles } from '@nestjs/common';

@Controller('cats')
export class CatsController {
  @Post('upload')
  uploadFile(@UploadedFile() file: Express.Multer.File): string {
    return `Uploaded file: ${file.originalname}`;
  }

  @Post('uploads')
  uploadFiles(@UploadedFiles() files: Express.Multer.File[]): string {
    return `Uploaded ${files.length} files`;
  }
}

這些裝飾器用於處理上傳檔案的請求。

@Ip()

@Ip() 裝飾器用於獲取客戶端的 IP 位址。

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

@Controller('cats')
export class CatsController {
  @Get()
  findCats(@Ip() ip: string): string {
    return `Client IP address: ${ip}`;
  }
}

這個裝飾器用於獲取客戶端的 IP 位址。

這些是一些常用的參數裝飾器,讓你可以更靈活地處理不同類型的請求。根據實際需要,你可以選擇適用於你的情境的裝飾器。

其他幾個都是取得參數或資料

唯獨「Res」是可以影響回傳的內容,像是狀態碼之類的
回傳資料的時候語法也跟其他人特別不一樣

來詳細問問有關Res的語法

@ Res (@Response)

https://ithelp.ithome.com.tw/upload/images/20231026/20135750KkqAOlldn3.png

當你使用 @Res() 裝飾器時,你可以在控制器方法中設置 HTTP 響應的各種屬性,例如狀態碼、標頭、回應主體等。

@Res() 裝飾器

首先,讓我們看一下如何在控制器方法中使用 @Res() 裝飾器:

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

@Controller('cats')
export class CatsController {
  @Get()
  findCats(@Res() response: Response): void {
    response.status(200).send('This is the response');
  }
}

在這個例子中,我們將 @Res() 裝飾器應用於 response 參數,這使得我們可以使用 response 來設置 HTTP 響應。

設置狀態碼

你可以使用 response.status() 方法來設置 HTTP 響應的狀態碼。例如,我們可以將狀態碼設置為 404:

response.status(404);

設置標頭

你可以使用 response.header() 方法來設置響應標頭。例如,我們可以設置 Content-Type 標頭:

response.header('Content-Type', 'application/json');

發送回應主體

最後,你可以使用 response.send() 方法來發送回應主體。這可以是文字、HTML、JSON 等。

response.send('This is the response body');

整合範例

現在,讓我們整合這些概念:

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

@Controller('cats')
export class CatsController {
  @Get()
  findCats(@Res() response: Response): void {
    response.status(200)
      .header('Content-Type', 'text/html')
      .send('<h1>Hello, cats!</h1>');
  }
}

在這個例子中,我們定義了一個 GET 路由,當用戶訪問時,我們設置了狀態碼為 200、Content-Type 標頭為 text/html,並發送了一個簡單的 HTML 頁面。

這就是如何在 NestJS 中使用 @Res() 裝飾器來控制 HTTP 響應的過程。希望這可以幫到你!如果還有其他問題,請隨時詢問。

特別注意到
回傳資料他使用了 .send('This is the response');

其他的範例裡,都是用return來回傳資料
唯獨這裡用.send來發送

來問問ChatGPT是不是有什麼規定或是限制,導致用@Res裝飾器的時候
不能用return來回傳資料嗎?
https://ithelp.ithome.com.tw/upload/images/20231026/201357503UxYSKPWzv.png

在 NestJS 中,如果你在控制器方法中使用了 @Res() 裝飾器並手動設置了狀態碼或標頭,則不能再使用 return 來回傳資料。

這是因為當你手動處理了響應物件 (response),NestJS 會假設你已經完全掌控了響應流程,因此不會再去理會控制器方法的 return

如果你需要回傳資料,你可以繼續使用 response.send() 方法來發送回應主體,或是使用其他方法來處理回應。

舉例來說:

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

@Controller('cats')
export class CatsController {
  @Get()
  findCats(@Res() response: Response): void {
    response.status(200)
      .header('Content-Type', 'text/html')
      .send('<h1>Hello, cats!</h1>');
  }
}

在這個例子中,我們手動設置了狀態碼和標頭,並使用 response.send() 來發送回應主體。如果你在這個方法中使用了 return,它將不會被執行。

所以,如果你需要控制狀態碼或標頭,建議繼續使用 response 物件來處理回應。如果你只是需要回傳資料,你可以使用 response.send() 或是其他相應的方法。

也就是說,用Res來控制status或是header
回應必須用.send() 來處理,使用 return 回傳是會被忽略掉的,不會執行的

Controller 其他進階內容

最後,還有什麼內容是有關Controller,但更為進階的內容呢
先詢問取得關鍵字,我們等下篇再來細細討論
https://ithelp.ithome.com.tw/upload/images/20231026/20135750DWfgxSdHDd.png

當然,除了基本的路由控制,NestJS 還提供了一些進階的功能和裝飾器,讓你可以更靈活地定制控制器的行為。

全域路由前綴

你可以使用 @Controller() 裝飾器的 path 參數來設置控制器的路由前綴。

@Controller('cats')
export class CatsController {
  // ...
}

在這個例子中,所有在 CatsController 中定義的路由都會以 /cats 開頭。

中間件

你可以使用 @UseGuards(), @UseInterceptors(), @UseFilters() 來應用中間件。

@Controller('cats')
@UseGuards(AuthGuard)
@UseInterceptors(LoggingInterceptor)
export class CatsController {
  // ...
}

這個例子中,AuthGuardLoggingInterceptor 都會應用到 CatsController 中的所有路由上。

自訂路由守衛 (Guards)

你可以使用 @UseGuards() 裝飾器來指定一個或多個路由守衛。

@Controller('cats')
@UseGuards(AuthGuard, RolesGuard)
export class CatsController {
  // ...
}

這個例子中,AuthGuardRolesGuard 都會應用到 CatsController 中的所有路由上。

自訂攔截器 (Interceptors)

你可以使用 @UseInterceptors() 裝飾器來指定一個或多個攔截器。

@Controller('cats')
@UseInterceptors(LoggingInterceptor, TransformInterceptor)
export class CatsController {
  // ...
}

這個例子中,LoggingInterceptorTransformInterceptor 都會應用到 CatsController 中的所有路由上。

自訂異常過濾器 (Filters)

你可以使用 @UseFilters() 裝飾器來指定一個或多個異常過濾器。

@Controller('cats')
@UseFilters(HttpExceptionFilter, CustomExceptionFilter)
export class CatsController {
  // ...
}

這個例子中,HttpExceptionFilterCustomExceptionFilter 都會應用到 CatsController 中的所有路由上。

自訂管道 (Pipes)

你可以使用 @UsePipes() 裝飾器來指定一個或多個管道。

@Controller('cats')
@UsePipes(ValidationPipe)
export class CatsController {
  // ...
}

這個例子中,ValidationPipe 會應用到 CatsController 中的所有路由上。

這些是一些進階的功能和裝飾器,讓你可以更靈活地定制控制器的行為。這些功能可以幫助你處理諸如身份驗證、日誌記錄、異常處理等方面的需求。根據實際需要,你可以在控制器上應用這些裝飾器以實現你的功能。

這些關鍵字和範例都可以先看過去就好,我們後續再討論

統整重點

https://ithelp.ithome.com.tw/upload/images/20231026/20135750Q6SZFGwq43.png

在這次的對話中,我們針對了 NestJS 控制器的基本概念以及一些進階功能進行了探討:

  1. 控制器基礎
    • 控制器是 NestJS 中用於處理請求和回應的元件。
    • 使用 @Controller() 裝飾器來定義一個控制器,並指定路由的前綴。
  2. 路由處理
    • 使用 @Get()@Post() 等裝飾器來定義路由和相應的 HTTP 方法。
  3. 參數裝飾器
    • 使用 @Param()@Body()@Query()@Headers() 等裝飾器來獲取請求中的不同類型的參數。
  4. 進階功能
    • 全域路由前綴、中間件、路由守衛、攔截器、異常過濾器以及管道都是可以應用在控制器上的進階功能。

結語:控制器是 NestJS 中極為重要的一環,它負責處理請求和回應,透過裝飾器可以實現豐富的功能。進階的功能如中間件、路由守衛等可以讓你更靈活地控制控制器的行為。希望這次的對話能幫助你對 NestJS 控制器有更深入的理解。如果你有其他問題,隨時向我詢問!

結語

本次的對話內容在這邊:
https://chat.openai.com/share/90e94168-02ef-4c9e-bb0e-0264fc4ad017

這篇講了很多裝飾器,不熟裝飾器的人aka我,就只能把裝飾器當作一種特殊語法來使用(?)
語法原理以及規定我也不太熟,於是!

加碼提問:
https://ithelp.ithome.com.tw/upload/images/20231026/20135750XpVwwxD3hm.png

裝飾器的原理涉及 JavaScript/TypeScript 語言的元程式設計(Metaprogramming)特性。裝飾器允許您修改類別、方法、屬性或參數的行為,通常是在它們被定義之後,但在運行時之前。以下是裝飾器的一般原理:

  1. 定義裝飾器函數:首先,您創建一個裝飾器函數。這個函數接受三個參數,分別是:
    • 如果是類別裝飾器,則為目標類別的原型。
    • 如果是方法、屬性或參數裝飾器,則為目標類別的原型(方法/屬性裝飾器),或目標類別的原型和方法/屬性名稱(參數裝飾器)。
    • 裝飾器應用的參數(如果有的話)。
  2. 使用 @ 符號應用裝飾器:在要修改的目標上使用 @ 符號,將裝飾器函數應用於目標。這告訴 JavaScript/TypeScript 在運行時調用裝飾器函數,並將目標和參數傳遞給它。
  3. 裝飾器函數的執行:當應用程式運行時,JavaScript/TypeScript 會調用裝飾器函數。在這個函數中,您可以修改目標的行為,例如添加屬性、方法、改變行為等。
  4. 最終行為:在運行時,目標(類別、方法、屬性或參數)將具有修改後的行為,這樣就可以在應用程式中使用了。

這是一個簡單的示例,演示如何創建一個簡單的方法裝飾器:

function MyMethodDecorator(target: any, methodName: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    // Modify the method's behavior here, e.g., add additional functionality
    console.log(`Calling method: ${methodName}`);
    return originalMethod.apply(this, args);
  };

  return descriptor;
}

class MyClass {
  @MyMethodDecorator
  myMethod() {
    console.log('Original method behavior');
  }
}

const instance = new MyClass();
instance.myMethod(); // This will call the modified method behavior

在這個示例中,MyMethodDecorator 裝飾器函數修改了 myMethod 的行為,並在調用該方法時添加了額外的功能。這演示了裝飾器的基本原理。

嗯。就是一種語法呢,可以使用是先定義好的function,額外的附加功能 (看上面內容的理解)
這個系列沒有要深入探討裝飾器的內容 (Angular相關教學可能比較會出現?)

下一篇會討論更多有關DTO、上述提到的中間件,以及傳入的型別驗證的部分
我是學會如何處理路由與參數的前端工程師一宵三筵,我們明天見!


上一篇
【Day42】ChatGPT請教教我:NestJS!(一)- 安裝 & 基本介紹 & Module概念
下一篇
【Day44】ChatGPT請教教我:NestJS!(三)- Controller & 資料驗證 !class-validator & class-transformer!
系列文
用ChatGPT詠唱來完成工作與點亮前後端技能樹56
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言