Nest.js快速啟動API專案
最近上了一個新專案,這個客戶管理一個龐大的任務和團隊叢集,而不同流程所適用的系統也不太一樣,比如salesforce,hubspots之類的。這次的新專案需要在另外兩個平臺之間做一些事情。目前只需要先封裝其中之一的API,因此我們選定使用NodeJS的框架Nest.js來實現這套API。
快速啟動
開啟nestjs專案有3種便捷的方式。
使用nest自帶的命令列工具
npm i -g @nestjs/cli
nest new project-name
即使不使用這種方式,也建議在node全域性安裝命令列工具,這樣可以方便的生成各種nestjs的模組,比如controller和service之類的。
直接使用starter專案
這裡還有一個用於啟動的樣例專案,可以直接使用。
git clone http://github.com/nestjs/typescript-starter.git my-app
cd my-app
npm install
npm run start
而且這個專案還附帶了Typescript。不過要記得把之前的git資訊刪掉。
用npm安裝所需的包
npm i --save @nestjs/core @nestjs/common rxjs reflect-metadata
直接安裝nestjs的core和common就可以,rxjs和reflext-metadata也是必需的。
這種方式比較乾淨,目錄什麼的需要自己建立。不過也可以使用命令列建立controller之類的,目錄會自動建立好。
總的來說,nestjs和其他語言API框架類似,很多東西可以自動生成或者無需編寫,所以約定的習慣非常重要,儘量不要建立一些“獨特”的結構,避免以後踩坑。
建立controller
建立好專案之後,我建立了一個controller,nest.js中controller可以通過修飾器直接提供路由,因此沒有一個route之類的檔案用於配置。
nest g controller projects
nest.js的目錄約定是按業務模組劃分,因為src目錄中會出現一個projects的目錄,該目錄下會生成一個projects.controller,以及附帶的單元測試。
建立service
接著建立service,用於封裝目標任務管理平臺關於Projects的API。
nest g service projects
建立controller和service都會自動加入到module裡,可以在每次生成後用git diff檢視一下生成了哪些程式碼,也好心理有數。
import { Controller, Get, Req } from '@nestjs/common';
import { Request } from 'express';
import { Project } from 'src/interfaces/project.interface';
import { ProjectsService } from './projects.service';
@Controller('projects')
export class ProjectsController {
constructor(private projectsService: ProjectsService) {}
@Get()
findAll(@Req() request: Request): Project[] {
return this.projectsService.findAll();
}
}
import { Injectable } from '@nestjs/common';
import { Project } from 'src/interfaces/project.interface';
@Injectable()
export class ProjectsService {
findAll(): Project[] {
return [];
}
}
結構和命名
另外我特別想說明一下的是,雖然我為controller和service都使用了相同的名稱,但並不是說他們是一一對應的。很多專案只是為了分層而分,controller和service都是一一對應的,其實並不正確。分層是因為它們擁有不同的意義,只有明確語義,才能在思維的過程中更好的掌握程式碼,也可以更好的複用,層次起到的是一種認知轉換的作用。如果只是把底層的物件毫無變化的映射出來,那這個過程是毫無意義的。
這裡的service在nestjs中其實是provider的一種,而provider的意義則是從各種不同的地方提供資料或其他東西。我使用的ProjectsService意義在於封裝另一個API,所以這個projects來源於目標任務管理平臺的API名稱。而controller的名稱projects指的是我建立的API所要提供的資料是project,只不過它們在這裡確實是同一個東西,所以名稱也一樣。
假設,現在的業務邏輯是需要從目標任務管理平臺獲取projects,之後過濾出兩種不同特性的projects,一種叫task任務,需要分配給人員;另一種叫note記錄,只是標記一下。它們擁有不同的特性。那麼我就會建立2個controller,taskController和noteController,但是它們都呼叫ProjectsService去使用不同的過濾條件獲取資料。
HTTP請求
使用nest.js官方的Http模組HttpModule
就可以向其他API發出請求。該模組其實也是封裝的Axios,所以用起來很方便。先安裝相關模組。
npm i --save @nestjs/axios axios
然後在app.module中引入。
import { HttpModule } from '@nestjs/axios';
...
@Module({
imports: [HttpModule], // 引入Http模組
controllers: [ProjectsController],
providers: [ProjectsService],
})
export class AppModule {}
處理Axios物件
在service中可以這樣處理http請求的返回值。
import { HttpService } from '@nestjs/axios';
import { Injectable } from '@nestjs/common';
import { map, Observable } from 'rxjs';
import { Project } from 'src/interfaces/project.interface';
import { AxiosResponse } from 'axios';
@Injectable()
export class ProjectsService {
constructor(
private readonly httpService: HttpService
) {}
findAll(): Observable<Project[]> {
return this.httpService.get('http://localhost:3000/api-json').pipe(
map((axiosResponse: AxiosResponse) => {
return axiosResponse.data;
})
);
}
}
因為Axios會包裹一層,用data作為統一的key,所以需要map出來。這裡的pipe和map方法都是來自rxjs。rxjs的核心就是Observable,使用響應式程式設計的方式,封裝了回撥和非同步方式的程式碼。因此這裡你看不到promise或者await/async之類的關鍵字。
配置
上面的請求,我只是使用了一個本地的json介面用於測試。要真正的呼叫目標平臺的API,還需要配置項,因為包括API token這種重要字串的一些值,需要放在環境變數中,不能直接放在程式碼被git提交。
所以我需要加上config的配置,安裝nest.js的config包,它封裝的其實是dotenv包,經常使用nodejs的話,應該會很熟悉這個包。
npm i --save @nestjs/config
同樣在app.module中引入config模組。
import { ConfigModule } from '@nestjs/config';
import configuration from './config/configuration';
...
imports: [
HttpModule,
ConfigModule.forRoot({
load: [configuration],
})
],
...
這裡使用forRoot是因為該模組是單例模式的。而傳入的引數load
可以把config物件載入。
引入的config/configuration
檔案是新建立的配置物件。
export default () => ({
port: parseInt(process.env.PORT, 10) || 3000,
runn: {
url: process.env.RUNN_API_URL,
token: process.env.RUNN_API_TOKEN
}
});
我配置了埠,以及API的URL和Token。
然後可能需要用到Typescript的介面,可以使用nest生成檔案。
nest g interface runn-config
export interface RunnConfig {
url: string
token: string
}
在service中就可以獲取這些配置項。
import { ConfigService } from '@nestjs/config';
import { RunnConfig } from 'src/interfaces/runn-config.interface';
...
constructor(
private readonly httpService: HttpService,
private configService: ConfigService
) {}
...
const config = this.configService.get<RunnConfig>('runn');
不要忘記在根目錄下建立.env
檔案填入配置的值。另外按習慣,可以建立.env.sample檔案,只包含key,沒有值,類似模板,被git提交管理。而.env檔案則被gitignore。只在本地保留。在伺服器上需要另外生成一份。
全域性新增headers
URL使用了,但Token需要在headers中新增。在app.module中使用HttpModule的register方法就可以配置其中封裝的Axios。不過由於token來自config,所以需要用比較麻煩的registerAsync,注入config後,在useFactory中使用。
...
imports: [
HttpModule.registerAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + configService.get('runn.token')
}
})
}),
...
],
...
這樣我就建立了一個基本API框架,並請求了一個簡單的目標任務管理系統的API獲取資料。
API文件
另外,由於客戶需要了解和測試我們的API,所以需要一個postman的api集合。我準備使用Swagger,這是一個API文件的自動生成工具,它會根據框架中定義的API和引數,自動生成一個頁面,包含所有的API和引數說明,以及可以直接請求該API。當然這需要修飾器的輔助。先安裝nestjs的swagger包。
npm i --save @nestjs/swagger
然後在main.ts
中引入並配置。
import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// swagger
const config = new DocumentBuilder()
.setTitle('My APIs')
.setDescription('My APIs documents')
.setVersion('1.0')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
// swagger end
await app.listen(3000);
}
bootstrap();
然後就可以通過http://localhost:3000/api
訪問該API文件頁面。不過目前所有API都會出現在default預設標籤下。官方示例中使用的addTag方法雖然可以新增一個標籤,但並不能指定某些API放入該標籤。我需要通過修飾器實現。
在controller的方法上使用@ApiTags('Project')
即可,該方法會被放置在Project標籤下。
除了API文件的頁面形式。http://localhost:3000/api-json
的JSON格式才是最重要的,可以使用它在Postman中直接匯入。
本文來源:Nest.js快速啟動API專案
- OceanBase榮獲OSCAR兩項大獎,開源已成主流開發模式
- linux根據inode編號刪除檔案
- 特約專訪 | 思否 CEO 高陽帶你瞭解 Code For Better _ Hackathon 冠軍團隊背後的故事
- Nest.js快速啟動API專案
- TiDB Hackathon 2022丨總獎金池超 35 萬!邀你喚醒程式碼世界的更多可能性!
- Go 為什麼能火?歸功於這 5 個方面
- JS 逆向百例】猿人學系列 web 比賽第五題:js 混淆 - 亂碼增強,詳細剖析
- 汪源:資料分析熱詞迭出,“三個統一”值得關注
- Go 為什麼能火?歸功於這 5 個方面
- Go 為什麼能火?歸功於這 5 個方面
- Go 為什麼能火?歸功於這 5 個方面
- Go 為什麼能火?歸功於這 5 個方面
- SpringBoot Vue Flowable,模擬一個請假審批流程!
- Go 為什麼能火?歸功於這 5 個方面
- 聊聊如何利用管道模式來進行業務編排(下篇)
- Golang 單例模式與sync.Once
- Golang 單例模式與sync.Once
- 如何通俗地理解「分散式系統」;Vue是否可以在一個專案中使用多個UI框架;大廠上線流程:先上前端還是後端|極客觀點
- 第二屆 1024 中國工程師文化日議程全覽,你不能錯過的 N 個理由
- 手寫程式語言-遞迴函式是如何實現的?