本系列文已出版成書「NestJS 基礎必學實務指南:使用強大且易擴展的 Node.js 框架打造網頁應用程式」,感謝 iT 邦幫忙與博碩文化的協助。如果對 NestJS 有興趣、覺得這個系列文對你有幫助的話,歡迎前往購書,你的支持是我最大的寫作動力!
很多時候我們會需要去串接第三方的 API,例如:綠界科技的金流服務、Binance 的 API 等,這時候如果第三方沒有提供相關的 SDK 讓我們使用的話,就必須自己用 HTTP Request 去存取對應的資料,早期的 node.js 開發人員可能會使用 request 來實作,但該函式庫現在已經被棄用了,取而代之的是 node-fetch 或 axios,而 Nest 內建了 HTTP Module,它是基於 axios
進行包裝的模組,讓 Nest 開發人員不必為使用哪個套件煩惱,HTTP Module 即裝即用!
注意:在第 8 版後的 NestJS 已經將 HTTP Module 獨立成
@nestjs/axios
套件,若使用第 8 版後的 NestJS 需要另外使用npm install @nestjs/axios
進行安裝。
HTTP Module 的 class
名稱為 HttpModule
,它匯出了一個 HttpService
的 Service,其提供 axios
的方法來處理 HTTP 請求,並且使用 Observable
的形式。
注意:想要知道
axios
具體有哪些方法可以查看官方說明。
以 app.module.ts
為例,將 HttpModule
導入:
import { HttpModule, Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [HttpModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
這裡我們借用一下 JSONPlaceholder 做為第三方 API,並使用 todos
的資源,將其資料結構用 interface
的方式存在 src/common/models
資料夾中的 todo.model.ts
:
export interface Todo {
userId: number;
id: number;
title: string;
completed: boolean;
}
調整一下 app.service.ts
的內容,透過 getTodos
方法去取得 todos
的資源:
注意:由於
Agent
的問題,這裡我們需要配置httpsAgent
的rejectUnauthorized
為false
以正常使用此 API。
import { HttpService, Injectable } from '@nestjs/common';
import { Agent } from 'https';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Todo } from './common/models/todo.model';
@Injectable()
export class AppService {
constructor(
private readonly http: HttpService
) {}
getTodos(): Observable<Todo> {
const httpsAgent = new Agent({ rejectUnauthorized: false });
return this.http.get('https://jsonplaceholder.typicode.com/todos', { httpsAgent }).pipe(
map((res) => res.data)
);
}
}
調整 app.controller.ts
,在 getTodos
中調用 AppService
的 getTodos
:
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get('/todos')
getTodos() {
return this.appService.getTodos();
}
}
透過 Postman 存取 http://localhost:3000/todos,會得到下方結果:
在上述範例中,會發現存取 JSONPlaceholder 的 todos
資源會碰到 Agent
的問題,如果有多個 API 都會碰到此問題,又不希望每次都要重複寫一樣的東西,這時候就可以運用 HttpModule
的 register
方法來配置預設值,而這個預設值可以配置的項目與 HttpService
各方法中的 options
相同,具體的內容可以參考官方說明。
這裡以 app.module.ts
為例,將 Agent
的配置設為預設值:
import { HttpModule, Module } from '@nestjs/common';
import { Agent } from 'https';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [
HttpModule.register({
httpsAgent: new Agent({ rejectUnauthorized: false })
})
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
接著調整 app.service.ts
,將本來配置好的 Agent
配置移除:
import { HttpService, Injectable } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Todo } from './common/models/todo.model';
@Injectable()
export class AppService {
constructor(
private readonly http: HttpService
) {}
getTodos(): Observable<Todo> {
return this.http.get('https://jsonplaceholder.typicode.com/todos').pipe(
map((res) => res.data)
);
}
}
最後,透過 Postman 存取 http://localhost:3000/todos,會成功獲取 todos
的資料:
HttpModule
有提供 registerAsync
方法,透過這個方法可以添加依賴的 Provider,並用工廠函式將其值帶入 HttpModule
,運用這樣的機制來注入 ConfigService
,進而將要配置的預設值帶入。
這邊來做個簡單的範例,先在專案目錄下新增 .env
並添加下方的環境變數:
HTTP_TIMEOUT=3000
修改 app.module.ts
的內容,在 registerAsync
匯入 ConfigModule
並在 injects
帶入 ConfigService
,最後在 useFactory
注入 ConfigService
:
import { HttpModule, Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { Agent } from 'https';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true
}),
HttpModule.registerAsync({
imports: [ConfigModule],
useFactory: (config: ConfigService) => ({
httpsAgent: new Agent({ rejectUnauthorized: false }),
timeout: config.get('HTTP_TIMEOUT')
}),
inject: [
ConfigService
]
})
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
這樣就可以順利將環境變數帶入至 HttpModule
來配置預設值了!
Nest 將 Http Request 相關功能直接打包成內建模組實在很方便,不必再花時間去選擇要使用哪個套件,也不必花時間將套件包裝成 Nest 的模組,直接注入 HttpService
即可使用。這裡附上今天的懶人包:
HttpModule
為內建模組,透過注入 HttpService
來使用 axios
的方法。HttpModule
的 register
來配置預設值。HttpModule
的 registerAsync
來取得注入 Provider 的值,進而配置預設值。