Nest.js快速啟動API項目過程詳解
快速啟動
最近上了一個新項目,這個客戶管理一個龐大的任務(wù)和團(tuán)隊集群,而不同流程所適用的系統(tǒng)也不太一樣,比如salesforce,hubspots之類的。這次的新項目需要在另外兩個平臺之間做一些事情。目前只需要先封裝其中之一的API,因此我們選定使用NodeJS的框架Nest.js來實現(xiàn)這套API。
開啟nestjs項目有3種便捷的方式。
使用nest自帶的命令行工具
npm i -g @nestjs/cli nest new project-name
即使不使用這種方式,也建議在node全局安裝命令行工具,這樣可以方便的生成各種nestjs的模塊,比如controller和service之類的。
直接使用starter項目
這里還有一個用于啟動的樣例項目,可以直接使用。
git clone https://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也是必需的。
這種方式比較干凈,目錄什么的需要自己創(chuàng)建。不過也可以使用命令行創(chuàng)建controller之類的,目錄會自動創(chuàng)建好。
總的來說,nestjs和其他語言API框架類似,很多東西可以自動生成或者無需編寫,所以約定的習(xí)慣非常重要,盡量不要創(chuàng)建一些“獨特”的結(jié)構(gòu),避免以后踩坑。
創(chuàng)建controller
創(chuàng)建好項目之后,我創(chuàng)建了一個controller,nest.js中controller可以通過修飾器直接提供路由,因此沒有一個route之類的文件用于配置。
nest g controller projects
nest.js的目錄約定是按業(yè)務(wù)模塊劃分,因為src目錄中會出現(xiàn)一個projects的目錄,該目錄下會生成一個projects.controller,以及附帶的單元測試。
創(chuàng)建service
接著創(chuàng)建service,用于封裝目標(biāo)任務(wù)管理平臺關(guān)于Projects的API。
nest g service projects
創(chuàng)建controller和service都會自動加入到module里,可以在每次生成后用git diff查看一下生成了哪些代碼,也好心理有數(shù)。
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 []; } }
結(jié)構(gòu)和命名
另外我特別想說明一下的是,雖然我為controller和service都使用了相同的名稱,但并不是說他們是一一對應(yīng)的。很多項目只是為了分層而分,controller和service都是一一對應(yīng)的,其實并不正確。分層是因為它們擁有不同的意義,只有明確語義,才能在思維的過程中更好的掌握代碼,也可以更好的復(fù)用,層次起到的是一種認(rèn)知轉(zhuǎn)換的作用。如果只是把底層的對象毫無變化的映射出來,那這個過程是毫無意義的。
這里的service在nestjs中其實是provider的一種,而provider的意義則是從各種不同的地方提供數(shù)據(jù)或其他東西。我使用的ProjectsService意義在于封裝另一個API,所以這個projects來源于目標(biāo)任務(wù)管理平臺的API名稱。而controller的名稱projects指的是我創(chuàng)建的API所要提供的數(shù)據(jù)是project,只不過它們在這里確實是同一個東西,所以名稱也一樣。
假設(shè),現(xiàn)在的業(yè)務(wù)邏輯是需要從目標(biāo)任務(wù)管理平臺獲取projects,之后過濾出兩種不同特性的projects,一種叫task任務(wù),需要分配給人員;另一種叫note記錄,只是標(biāo)記一下。它們擁有不同的特性。那么我就會創(chuàng)建2個controller,taskController和noteController,但是它們都調(diào)用ProjectsService去使用不同的過濾條件獲取數(shù)據(jù)。
HTTP請求
使用nest.js官方的Http模塊HttpModule
就可以向其他API發(fā)出請求。該模塊其實也是封裝的Axios,所以用起來很方便。先安裝相關(guān)模塊。
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作為統(tǒng)一的key,所以需要map出來。這里的pipe和map方法都是來自rxjs。rxjs的核心就是Observable,使用響應(yīng)式編程的方式,封裝了回調(diào)和異步方式的代碼。因此這里你看不到promise或者await/async之類的關(guān)鍵字。
配置
上面的請求,我只是使用了一個本地的json接口用于測試。要真正的調(diào)用目標(biāo)平臺的API,還需要配置項,因為包括API token這種重要字符串的一些值,需要放在環(huán)境變量中,不能直接放在代碼被git提交。
所以我需要加上config的配置,安裝nest.js的config包,它封裝的其實是dotenv包,經(jīng)常使用nodejs的話,應(yīng)該會很熟悉這個包。
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是因為該模塊是單例模式的。而傳入的參數(shù)load
可以把config對象載入。
引入的config/configuration
文件是新創(chuàng)建的配置對象。
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');
... const config = this.configService.get<RunnConfig>('runn');
不要忘記在根目錄下創(chuàng)建.env
文件填入配置的值。另外按習(xí)慣,可以創(chuàng)建.env.sample文件,只包含key,沒有值,類似模板,被git提交管理。而.env文件則被gitignore。只在本地保留。在服務(wù)器上需要另外生成一份。
全局添加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') } }) }), ... ], ...
這樣我就創(chuàng)建了一個基本API框架,并請求了一個簡單的目標(biāo)任務(wù)管理系統(tǒng)的API獲取數(shù)據(jù)。
API文檔
另外,由于客戶需要了解和測試我們的API,所以需要一個postman的api集合。我準(zhǔn)備使用Swagger,這是一個API文檔的自動生成工具,它會根據(jù)框架中定義的API和參數(shù),自動生成一個頁面,包含所有的API和參數(shù)說明,以及可以直接請求該API。當(dāng)然這需要修飾器的輔助。先安裝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都會出現(xiàn)在default默認(rèn)標(biāo)簽下。官方示例中使用的addTag方法雖然可以添加一個標(biāo)簽,但并不能指定某些API放入該標(biāo)簽。我需要通過修飾器實現(xiàn)。
在controller的方法上使用@ApiTags('Project')
即可,該方法會被放置在Project標(biāo)簽下。
除了API文檔的頁面形式。http://localhost:3000/api-json的JSON格式才是最重要的,可以使用它在Postman中直接導(dǎo)入。
以上就是Nest.js快速啟動API項目過程詳解的詳細(xì)內(nèi)容,更多關(guān)于Nest.js快速啟動API的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JS數(shù)組扁平化的方法合集(遞歸,while循環(huán),flat)
數(shù)組扁平化也是面試??碱}之一,今天就和大家簡單分享一下常見的數(shù)組扁平方法,這題其實主要考察的是遞歸思想,因為當(dāng)數(shù)組里面嵌套非常多層數(shù)組的時候只能通過循環(huán)遞歸來進(jìn)行扁平,本次分享主要也是分享本題的遞歸思想,需要的朋友可以參考下2024-06-06在JavaScript中調(diào)用Java類和接口的方法
這篇文章主要講述如何在JavaScript腳本語言中調(diào)用Java類和接口,對大家的學(xué)習(xí)和工作有一定的參考借鑒價值,有需要的朋友們下面來一起看看吧。2016-09-09如何實現(xiàn)JavaScript動態(tài)加載CSS和JS文件
這篇文章主要為大家詳細(xì)介紹了JavaScript動態(tài)加載CSS和JS文件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2015-10-10在JavaScript中使用mqtt.js的詳細(xì)過程
這篇文章主要介紹了在JavaScript中使用mqtt.js的相關(guān)知識,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-04-04