npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@tapnow/nestjs-common

v1.0.2

Published

TapNow-NestJS-Common 的主要目标是为了各个服务聚焦于业务需求,避免各种模块初始化(如Logger,DataBase等)、公用服务等代码重复出现在各个微服务中。TapNow-NestJS-Common 提供一个`CommonModule`来初始化服务需要的模块,提供一些公用的装饰器和Service类来简化业务代码,以提高开发效率,减少维护成本。 `CommonModule` 是一个全局模块,默认会初始化`ConfigModule`, `LoggerModule`(nestjs-pino)

Downloads

2

Readme

TapNow-NestJS-Common

TapNow-NestJS-Common 的主要目标是为了各个服务聚焦于业务需求,避免各种模块初始化(如Logger,DataBase等)、公用服务等代码重复出现在各个微服务中。TapNow-NestJS-Common 提供一个CommonModule来初始化服务需要的模块,提供一些公用的装饰器和Service类来简化业务代码,以提高开发效率,减少维护成本。 CommonModule 是一个全局模块,默认会初始化ConfigModule, LoggerModule(nestjs-pino),HttpModule, SequelizeModule, 可根据微服务自身需要选择是否初始化RedisModule, RabbitMQModule

安装

yarn add tapnow-nestjs-common

配置

在初始化Module时,需要定义每个服务自己的配置项,比如数据库等。配置定义如下:

export interface ConfigOptions {
  namespaces: any[]
  schema: any
}

namespaces

ConfigModule允许定义和加载多个自定义配置文件,使用registerAs()函数返回namespaces配置对象,详细介绍可查看官方文档。配置主要分为TapNow-NestJS-Common各模块所需要的配置项和微服务自身业务所需要的配置项。 TapNow-NestJS-Common 详细配置如下:

export default registerAs('common', () => ({
  withCore: {
    pino: {
      // LoggerModule配置
    },
  },
  withSequelize: {
    // sequelize配置
  },
  withRedis: {
    // redis 配置
  },
  withRabbitMQ: {
    // rabbit MQ 配置
  },
  jwt: {
    secret: {
      client: 'XXXX',   // for web client user, x-auth-schema === CLIENT will use this secret
      merchant: 'XXXX', // for merchant user, x-auth-schema === MERCHANT will use this secret
      admin: 'XXXX',    // for admin user, x-auth-schema === ADMIN will use this secret
      api: 'XXXX',      // for partner backend, x-auth-schema === API will use this secret
      internal: 'XXXX', // for internal service, x-auth-schema === INTERNAL will use this secret
    },
  },
}))

配置文件示例可查看 test/config/common.config.ts

schema

如果未提供所需的环境变量或它们不符合某些验证规则,则在应用程序启动期间抛出异常是标准做法。详细信息可查看官方文档 schema示例可查看test/config/schema.ts

初始化

定义好配置文件后,便可以开始初始化工作了。

@Module({
  imports: [CommonModule.forRoot(config, { withRedis: true, withRabbitMQ: true })],
  controllers: [],
  providers: [],
})
export class AppModule {}

async function bootstrap() {
  const app = await NestFactory.create(AppModule, { cors: true })
  await app.listen(3000)
}
bootstrap()

Module

LoggerModule

首先设置logger:

import { Logger } from 'nestjs-pino';

const app = await NestFactory.create(AppModule, { bufferLogs: true });
app.useLogger(app.get(Logger));

推荐Logger使用方式

import { PinoLogger, InjectPinoLogger } from 'nestjs-pino';

export class MyService {
  constructor(
    private readonly logger: PinoLogger
  ) {
    // Optionally you can set context for logger in constructor or ...
    this.logger.setContext(MyService.name);
  }

  constructor(
    // ... set context via special decorator
    @InjectPinoLogger(MyService.name)
    private readonly logger: PinoLogger
  ) {}

  foo() {
    // PinoLogger has same methods as pino instance
    this.logger.trace({ foo: 'bar' }, 'baz %s', 'qux');
    this.logger.debug('foo %s %o', 'bar', { baz: 'qux' });
    this.logger.info('foo');
  }
}

SequelizeModule

Sequelize的Model已定好了createdAt, updatedAt, deletedAt,不需要再额外定义了,直接继承Model就好

createdAt?: Date | any;
updatedAt?: Date | any;
deletedAt?: Date | any;

TapNow-NestJS-Common 提供了paginate函数来处理分页查询。

RedisModule

RedisModule提供RedisService, RedlockService, SessionService三个service 类。RedisService 提供一个redis实例来存储数据。RedlockService 提供分布式锁,获取单一资源锁用lock()lockWrapper会在函数执行完成后,自动释放锁资源。

RabbitModule

RabbitMQTaskService提供服务自己发布消息,自己处理消息的模式。 比如发送邮件,我们先发布一个发送邮件的任务

const EMAIL_TASK = 'email_task'

class EmailService {
  constructor(private readonly rabbitMQTaskService: RabbitMQTaskService) {}

  async sendEmail(payload) {
    return rabbitMQTaskService.publishTask({
      msgName: EMAIL_TASK,
      payload,
    })
  }
}

然后监听EMAIL_TASK event,发送邮件

@Injectable()
class EmailWork {
  @OnEvent(EMAIL_TASK)
  async charge(payload: PublishPayload) {
    // sending email here
  }
}

在业务里需要发送邮件时,调用EmailServicesendEmail即可。 RabbitTopicMQService提供对其他服务发布消息或者订阅其他服务发布的消息功能。若消费服务失败,消息将被加入到死信队列。 例如: 支付服务需要将支付成功告知Partner,此时支付服务需要发布一条支付成功的消息:

const PAYMENT_MESSAGE = 'payment_message'
const PAYMENT_SUCCESS = 'payment_success'

class NotificationService {
  constructor(private readonly rabbitMQTopicService: RabbitTopicMQService) {}

  async sendMessage(payload) {
    return rabbitMQTopicService.publishMessage(PAYMENT_MESSAGE, {
      msgName: PAYMENT_SUCCESS,
      payload,
    })
  }
}

Partner订阅支付服务的支付消息:

const QUEUE_NAME = 'payment_queue'
const DEAD_QUEUE_NAME = 'payment_dead_queue'

@Injectable()
class PaymentMessage implements OnApplicationBootstrap {
  constructor(private readonly rabbitMQTopicService: RabbitTopicMQService) {}

  // subscribe payment message
  async onApplicationBootstrap() {
    await rabbitMQTopicService.subscribe(
        QUEUE_NAME,
        DEAD_QUEUE_NAME,
        `#.${PAYMENT_MESSAGE}.#`,
        {
          durable: true,
          autoDelete: false,
        },
      )
  }

  @OnEvent(PAYMENT_SUCCESS)
  async onPaymentSuccess(payload: PublishPayload) {
    // do something when received the payment successful message
  }
}

Request

TapNow-NestJS-Common提供了一些公用的装饰器来简化API实现。

import { ClientAuth, CurrentUser, ApiPropertyOptional, ApiProperty, ApiBaseResult } from 'tapnow-nestjs-common'

class PartnerRequest {
  @ApiPropertyOptional({
    description: 'Partner名字',
    example: 'Kitty',
  })
  @IsString()
  name?: string
}

class PartnerResponse {
  ApiProperty({
    description: 'Partner的ID',
    example: 'p_123e',
  })
  id: string,

  ApiProperty({
    description: 'Partner名字',
    example: 'Kitty',
  })
  name: string,
}

@Controller()
class TestingController {
  @ApiBaseResult(PartnerResponse, 200, '获取Partner信息')
  @Get('fake/:id')
  @AdminAuth()
  getPartner(@CurrentUser() user, @Query() query: PartnerRequest)
    : Promise<PartnerResponse> {
    // some code here, and return partner finally, and TapNow-NestJS-Common will transform it to { code, message, data: partner }
  }
}

如上代码实现了一个获取Partner信息的API,这个API是提供给管理后台的,所以需要进行AdminAuth权限校验。TapNow-NestJS-Common已设置全局的ValidationPipe,因此会对PartnerRequest请求参数进行校验。 PartnerRequest + ApiBaseResult定义了Swagger文档中该API的完整描述。

Response

TapNow-NestJS-Common 会捕捉请求范围内的异常并返回错误信息,对于正常的请求结果会转换成{ code, message, data }的数据结构,其中data是api返回的数据。

Auth

TapNow-NestJS-Common提供了PUBLIC, CLIENT, ADMIN, MERCHANT, API, INTERNAL, DEBUG这几种授权方式,并提供了相应的装饰器。由于授权用到了session,所以必须加载RedisModule。