乐趣区

关于javascript:Nestjs快速启动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 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 也是必须的。

这种形式比拟洁净,目录什么的须要本人创立。不过也能够应用命令行创立 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 中间接导入。

原博客连贯

退出移动版