Nest.js框架项目初始化实践

Nest.js框架项目初始化实践

实现背景:

Nest (NestJS) 是一个用于构建高效、可扩展的 Node.js 服务器端应用程序的开发框架。它利用 JavaScript 的渐进增强的能力,使用并完全支持 TypeScript (仍然允许开发者使用纯 JavaScript 进行开发),并结合了 OOP (面向对象编程)、FP (函数式编程)和 FRP (函数响应式编程)。
Nest.js官方文档
Nest.js是一个使用TS开发的框架,使用了很多java相关的思想,很适合前端与JS工程师了解,此篇文章是我的一次项目初始化实践。
该项目数据库使用了 MongoDB、项目依赖库管理由 yarn 构建,同时集成了 Swagger 接口文档

项目实现:

init:
$ npm i -g @nestjs/cli
$ nest new nest-cil # your project-name

1、package manager 我们选择 yarn 回车即可

package manager

2、稍等片刻即可创建成功,此时的项目结构如下:
初始项目结构

Install Dependencies:
$ yarn add mongoose @nestjs/mongoose # mongoDB 操作库 ( mongo版 sequelize )
$ yarn add @nestjs/swagger swagger-ui-express fastify-swagger # swagger 相关依赖
$ yarn add class-validator # 数据校验依赖库
Config Project & Schema
1、配置logger模块:

我们在根目录新建loggor文件夹,新建以下三个文件:
在这里插入图片描述

// logger.service.ts
import { Injectable, Scope, Logger } from '@nestjs/common';

@Injectable({ scope: Scope.TRANSIENT })
export class LoggerService extends Logger {}


// logger.module.ts
import { Module } from '@nestjs/common';
import { LoggerService } from './logger.service';

@Module({
  imports: [],
  controllers: [],
  providers: [LoggerService],
  exports: [LoggerService],
})
export class LoggerModule {}


// logger.service.spec.ts 这文件没那么重要
import { Test, TestingModule } from '@nestjs/testing';
import { LoggerService } from './logger.service';

describe('LoggerService', () => {
  let service: LoggerService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [LoggerService],
    }).compile();

    service = module.get<LoggerService>(LoggerService);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });
});

2、添加Schema相关模块 (数据库操作模块):

新建一个文件夹(文件名为表名),创建以下文件
在这里插入图片描述

1、DTO-数据传输对象

// deviceType.dto.ts 数据传输对象
import { IsNotEmpty, MinLength, MaxLength } from 'class-validator'; // 校验
import { ApiProperty } from '@nestjs/swagger';

export class DeviceTypeDto {
  @ApiProperty({ example: 1, description: '设备编号' })
  @IsNotEmpty({ message: '设备编号不能为空' })
  readonly deviceTypeNo: number;

  @ApiProperty({ example: 'Nick设备', description: '设备名' })
  @IsNotEmpty({ message: '设备名不能为空' })
  readonly name: string;

  @ApiProperty({ example: '这是备注', description: '备注' })
  readonly remarks: string;
}

2、Interface-数据范式

// deviceType.interface.ts 数据范式
export interface DeviceType {
  id?: string;
  deviceTypeNo?: string;
  name?: string;
  remarks?: string;
}

3、schema-数据表结构

// deviceType.schema.ts 数据表结构
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

@Schema()
export class DeviceType extends Document {
  @Prop({ type: Number, required: true })
  deviceTypeNo: string;

  @Prop({ type: String, required: true })
  name: string;

  @Prop({ type: String, required: false })
  remarks: string;
}

export const DeviceTypeSchema = SchemaFactory.createForClass(DeviceType);

4、service-方法函数

// deviceType.service.ts 数据表结构
import { Injectable } from '@nestjs/common';
import { DeviceType } from './schemas/deviceType.schema';
import { Model } from 'mongoose';
import { InjectModel } from '@nestjs/mongoose';
import { DeviceTypeDto } from './dto/deviceType.dto';

@Injectable()
export class DeviceTypeService {
  constructor(@InjectModel('DeviceType') private readonly deviceTypeModel: Model<DeviceType>) {}

  async findAll(): Promise<DeviceType[]> {
    return this.deviceTypeModel.find().exec();
  }

  async findById(id: string): Promise<DeviceType> {
    return id.match(/^[0-9a-fA-F]{24}$/)
      ? await this.deviceTypeModel.findOne({ _id: id })
      : null;
  }

  async create(item: DeviceTypeDto) {
    const newItem = new this.deviceTypeModel(item);
    return newItem.save();
  }

  async delete(id: string): Promise<DeviceType> {
    return this.deviceTypeModel.findByIdAndRemove(id);
  }

  async update(id: string, deviceType: DeviceTypeDto): Promise<DeviceType> {
    return await this.deviceTypeModel.findByIdAndUpdate(id, deviceType, {new: true});
  }
}

5、controller-接口路由控制器

// deviceType.controller.ts 数据表结构
import { Body, Controller, Delete, Get, Param, Post, Put, UsePipes } from '@nestjs/common';
import {
  ApiOperation,
  ApiTags,
  ApiQuery,
  ApiBody,
  ApiResponse,
} from '@nestjs/swagger';
import { DeviceTypeDto } from './dto/deviceType.dto';
import { DeviceTypeService } from './deviceType.service';
import { DeviceType } from './interfaces/deviceType.interface';
import { LoggerService } from 'src/logger/logger.service';
import { ValidationPipe } from'../pipe/validation.pipe';

@Controller('deviceType')
@ApiTags('deviceType')
export class DeviceTypeController {
  constructor(
    private readonly deviceTypeService: DeviceTypeService,
    private logger: LoggerService,
  ) {}

  @Get('/queryAll')
  @ApiOperation({ summary: '查找所有设备类型' })
  async findAll(): Promise<DeviceType[]> {
    this.logger.debug('Get All Items Endpoint');
    return this.deviceTypeService.findAll();
  }

  @Get('queryOne/:id')
  @ApiOperation({ summary: '根据ID查找设备类型' })
  // @ApiQuery({ name: 'limit', required: true })
  async findById(@Param() param): Promise<DeviceType> {
    return this.deviceTypeService.findById(param.id);
  }

  @UsePipes(new ValidationPipe()) // 使用管道验证
  @Post('/create')
  @ApiOperation({ summary: '创建设备类型', description: '创建设备类型' })
  async create(@Body() itemDTO: DeviceTypeDto): Promise<DeviceType> {

    return this.deviceTypeService.create(itemDTO);
  }

  @Put('update/:_id')
  @ApiOperation({ summary: '更新设备类型' })
  @ApiBody({ type: DeviceTypeDto, description: '参数可选' })
  @ApiResponse({
    status: 200,
    description: '成功返回200,失败返回400',
    type: DeviceTypeDto,
  })
  async update(@Param() param, @Body() DeviceTypeDto: DeviceTypeDto): Promise<DeviceType> {
    return this.deviceTypeService.update(param.id, DeviceTypeDto);
  }

  @Delete('delete/:id')
  @ApiOperation({ summary: '删除设备类型' })
  async delete(@Param() param): Promise<DeviceType> {
    return this.deviceTypeService.delete(param.id);
  }
}

5、module-模块构造器

// deviceType.module.ts 数据表结构
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { LoggerModule } from 'src/logger/logger.module';
import { LoggerService } from 'src/logger/logger.service';
import { DeviceTypeController } from './deviceType.controller';
import { DeviceTypeService } from './deviceType.service';
import { DeviceTypeSchema } from './schemas/deviceType.schema';

@Module({
  imports: [
    MongooseModule.forFeature([{ name: 'DeviceType', schema: DeviceTypeSchema }]),
    LoggerModule,
  ],
  controllers: [DeviceTypeController],
  providers: [DeviceTypeService, LoggerService],
})
export class DeviceTypeModule {}

3、数据库Config & env:
// config/configuration.ts 数据表结构
export default () => ({
  // port: 27017,
  port: 3000,
  database: {
    uri: `mongodb://${process.env.DB_HOST_D}:${process.env.DB_PORT_D}/${process.env.DB_NAME_D}`,
    // uri: `${process.env.DB_NAME_D}`,
  },
});

// .env 项目根目录创建
NODE_ENV=development

DB_HOST_D=127.0.0.1 //数据库地址
DB_NAME_D=testMongo //数据库名
DB_PORT_D=27017 // 端口

3、app.module & main:
// app.module.ts 数据表结构
import { LoggerModule } from './logger/logger.module';
import { DeviceTypeModule } from './deviceType/deviceType.module';
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { ConfigModule, ConfigService } from '@nestjs/config';
import configuration from './config/configuration';

@Module({
  imports: [
    LoggerModule
    DeviceTypeModule,
    ConfigModule.forRoot({
      isGlobal: true,
      load: [configuration],
    }),
    MongooseModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: (configService: ConfigService) => ({
        uri: `${configService.get('database.uri')}`,
      }),
      inject: [ConfigService],
    }),
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}

// main.ts 项目根目录创建
import { ConfigService } from '@nestjs/config';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  const configService: ConfigService = app.get(ConfigService);
  // swagger 相关配置,具体在controller中配置
  const swaggerOptions = new DocumentBuilder()
      .setTitle('ez-DeviceLib-文档')  // 文档标题
      .setDescription('DeviceLib-api-说明')  // 文档描述
      .setVersion('1.0')  // 文档版本
      .addBasicAuth() // 鉴权相关
      .build(); // 创建

  //创建swagger
  const document = SwaggerModule.createDocument(app, swaggerOptions);
  //启动swagger
  SwaggerModule.setup('doc', app, document);

  await app.listen(configService.get('port'));
}
bootstrap();

Start Databases:
1、下载mongoDB并配置:

Win:https://www.mongodb.com/download-center/community
Linux:https://www.runoob.com/mongodb/mongodb-linux-install.html
Mac:https://www.mongodb.com/download-center#community

2、配置完成后启动:
$ sudo mongod --dbpath=/Users/ezpro/data
$ mongo

以下结果即为启动成功:
在这里插入图片描述

Start Project:
$ npm start
Swagger:

本地浏览器打开 http://localhost:(env-port)/doc/
Swagger界面

项目Github地址:

nest-cil:https://github.com/hyxONick/nest-cil

总结:

TS、Nest.js相较于传统JS与Koa等框架相比规范性有了很大的提升,加上Nest的OOP、FP和FRP等类java思想,让其更加严谨与规范,更像是一门规范的后台语言。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值