创建项目很简单,nest-cli一键创建,关键是如何基于nestjs现有能力进行架构设计。
架构设计
项目背景
项目涉及的底层数据全部来自于公司的一个公共服务(jsf),该公共服务可对接口进行发布和订阅,同时提供各种协议的接口供第三方使用。我们的项目都是基于该服务提供的接口对数据进行二次加工和使用。
我的设想
我想构建的服务,类似微服务架构,有多个产品(ge和dm或者更多),各个产品之间有重合的业务,这部分需要共享,也有各自定制化的部分由各个产品自己管理,虽可能存在相互依赖,但需要独立部署。
基于以上思路,得到如下架构模型:
-
JSF-SERVER
从公共服务获取数据,有多种方式获取(TCP、Http、RPC、Grpc),同时可以暴露http接口给客户端直接获取底层数据。(有些不需要二次加工的数据可以直接吐出)。第三方服务也可通过TCP协议与服务建立通信,获取数据。 -
Ge-server和Dm-server
基础服务,暴露http接口给客户端使用 -
libs
存放公共模块,比如登陆、鉴权、拦截器等
DEMO地址:
项目搭建
项目初始化
web 框架选择fastify代替Express,因其网络性能,详见附件性能评测
# 初始化项目
npm install @nestjs/cli -g
nest new nest-server-demo
# 安装依赖
npm uninstall @nestjs/platform-express
npm install @nestjs/{platform-fastify,microservices} class-transformer class-validator --save
# 创建应用
nest g app ge
nest g app dm
nest g jsf
# 创建公共模块,修改前缀为@libs
nest g library common
改造微服务
暴露微服务
路径:apps/jsf/main.ts
declare const module: any;
import { NestFactory } from '@nestjs/core';
import { JsfModule } from './jsf.module';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
async function bootstrap() {
const app = await NestFactory.createMicroservice<MicroserviceOptions>(JsfModule, {
transport: Transport.TCP,
options: {
port: 4000,
},
});
await app.listen();
if (module.hot) {
module.hot.accept();
module.hot.dispose(() => app.close());
}
}
bootstrap();
发布消息
- 路径 apps/jsf/jsf.controller.ts
import { Controller, Get } from '@nestjs/common';
import { JsfService } from './jsf.service';
import { MessagePattern } from '@nestjs/microservices';
@Controller()
export class JsfController {
constructor(private readonly jsfService: JsfService) {}
@MessagePattern({ cmd: 'getHelloX' })
getHelloMessage(name: string): string {
return this.jsfService.getHelloMessage(name);
}
}
- 路径 apps/jsf/jsf.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class JsfService {
getHelloMessage(name: string): string {
return `Hello ${name}!`;
}
}
注册微服务
- 路径:apps/ge/ge.module.ts
import { Module } from '@nestjs/common';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { GeController } from './ge.controller';
import { GeService } from './ge.service';
@Module({
imports: [
ClientsModule.register([
{
name: 'NEST_SERVICE',
transport: Transport.TCP,
options: {
port: 4000,
},
},
]),
],
controllers: [GeController],
providers: [GeService],
})
export class GeModule {}
注入微服务并调用
- 路径 apps/ge/ge.service.ts
import { Inject, Injectable } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import { Observable } from 'rxjs';
@Injectable()
export class GeService {
constructor(@Inject('NEST_SERVICE') private readonly client: ClientProxy) {}
getHelloMessage(name: string): Observable<string> {
return this.client.send<string>({ cmd: 'getHelloX' }, name);
}
}
创建http接口供客户端使用
- 路径:apps/ge/ge.controller.ts
import { Controller, Get, Param } from '@nestjs/common';
import { GeService } from './ge.service';
@Controller()
export class GeController {
constructor(private readonly geService: GeService) {}
@Get(':name')
getHello(@Param() params) {
return this.geService.getHelloMessage(params.name);
}
}
启动项目
安装concurrently,同时启动多应用并改造start脚本
"start": "concurrently --kill-others \"npm run start:ge\" \"npm run start:jsf\"",
"start:ge": "nest start ge --watch",
"start:jsf": "nest start jsf --watch",
"start:dm": "nest start dm --watch",
npm install concurrently -D
npm run start
防伪接口:localhost:3000/songmeinuo
注意:修改apps/dm/dm.main.ts的端口号,否则会冲突
建立代码规约
npm install kaqiinono-script -D
dm-rule
详见:
代码规范脚本自动化
利用npm bin创建可执行命令实现项目代码规范自动化
附录
web框架性能评测