@acheetahk/nest-tools

work with nest.js backend

Usage no npm install needed!

<script type="module">
  import acheetahkNestTools from 'https://cdn.skypack.dev/@acheetahk/nest-tools';
</script>

README

@acheetahk/nest-tools

@acheetahk/nest-tools 🔧 . the nest.js server tools.


codecov build npm

Please use version greater than 2.0.0

Methods Nav

Installation

npm install @acheetahk/nest-tools

cnpm install @acheetahk/nest-tools

yarn add @acheetahk/nest-tools

Dependencies

{
  "@nestjs/common": "^7.0.0",
  "@nestjs/swagger": "^4.7.2",
  "@types/express": "^4.17.8",
  "@types/uuid": "^8.3.0",
  "class-transformer": "^0.3.1",
  "class-validator": "^0.12.2",
  "rxjs": "^6.6.3"
}

Usage

import {
  IP,
  User,
  Headers,
  DtoPipe,
  HealthModule,
  RequestFilter,
  FormatInterceptor,
  LoggerInterceptor,
  RequestIdInterceptor,
} from '@acheetahk/nest-tools';

default

logger demo

export class SimpleLogger {
  public info(value: string) { console.log(value) }
  public error(value: string) { console.log(value) }
  public debug(value: string) { console.log(value) }
  public fatal(value: string) { console.log(value) }
  public trace(value: string) { console.log(value) }
  public warn(value: string) { console.log(value) }
}

response status & code

// default response http exception status code
export const statusCodes: StatusCodes = {
  200: 'Success',
  400: 'BadRequest',
  401: 'Unauthorized',
  403: 'Forbidden',
  404: 'NotFound',
  408: 'RequestTimeout',
  422: 'Unprocessable',
  500: 'InternalServerError',
  501: 'NotImplemented',
  502: 'BadGateway',
  503: 'ServiceUnavailable',
};

// default response status
export const statusMaps: StatusMaps = new Map([
  [
    'Success',
    {
      code: 0,
      zh: '请求成功',
      en: 'Request Success',
    },
  ],
  [
    'NotFound',
    {
      code: 1000001,
      zh: '未找到访问资源',
      en: 'Request NotFound',
    },
  ],
  [
    'Forbidden',
    {
      code: 1000002,
      zh: '拒绝访问',
      en: 'Request Forbidden',
    },
  ],
  [
    'Unauthorized',
    {
      code: 1000003,
      zh: '无权限访问',
      en: 'Request Unauthorized',
    },
  ],
  [
    'Unprocessable',
    {
      code: 1000004,
      zh: '参数有误',
      en: 'Request Unprocessable',
    },
  ],
  [
    'NotImplemented',
    {
      code: 1000005,
      zh: '处理失败',
      en: 'Request NotImplemented',
    },
  ],
  [
    'BadGateway',
    {
      code: 1000006,
      zh: '网关访问异常',
      en: 'BadGateway',
    },
  ],
  [
    'InternalServerError',
    {
      code: 1000007,
      zh: '服务异常',
      en: 'InternalServerError',
    },
  ],
  [
    'BadRequest',
    {
      code: 1000008,
      zh: '请求有误',
      en: 'BadRequest',
    },
  ],
  [
    'RequestTimeout',
    {
      code: 1000009,
      zh: '请求超时',
      en: 'Request Timeout',
    },
  ],
]);

ip

validationIp

/**
 * Is a correct IP address
 *
 * @param ipStr `string` ipv4 or ipv6
 *
 * @returns boolean
 */
validationIp('2001:3CA1:010F:001A:121B:0000:0000:0010') // true

getIpByRequest

/**
 * Get the IP from the request
 *
 * @param requset `Request`
 *
 * @returns string
 */
getIpByRequest(request) // ip string

pipe

DtoPipe

@Module({ imports: [HealthModule]})
export class CoreModule {}

const app = await NestFactory.create(CoreModule, { cors: true });

app.useGlobalPipes(new DtoPipe()); // 👀
await app.listen(3000);

filter

RequestFilter

/**
 * Instantiation RequestFilter
 * 
 * @param logger `Logger` Must be has `error` and `info` methods.
 * @param options `StatusOptions`
 * @param options.codes `StatusCodes` response http exception status code.
 * @param options.status `StatusMaps` response status.
 * @param options.language `'zh' | 'en'`
 */
@Module({ imports: [HealthModule]})
export class CoreModule {}

const app = await NestFactory.create(CoreModule, { cors: true });

// Use the default configuration
app.useGlobalFilters(new RequestFilter(logger));

// or
app.useGlobalInterceptors(new RequestFilter<SimpleLogger>(logger));

// Custom your `statusCodes` `statusMaps`
const options = { statusCodes, statusMaps, language: ('en' as const) };

app.useGlobalFilters(new RequestFilter(logger, options));

error log

[Error] [GET] /demo/dto ==> [1000004] 
[Request] [ID]   629e2ca9-1d40-41d5-9c18-e4b775df3793 
[Request] [Query]   {} 
[Request] [Body]    {} 
[Request] [Headers] {"accept":"application/json, text/plain, */*","user-agent":"axios/0.21.0","host":"localhost:6666","connection":"close","x-api-request-id":"629e2ca9-1d40-41d5-9c18-e4b775df3793"} 
[Response] [Detail]  {"code":1000004,"message":"test","requestId":"629e2ca9-1d40-41d5-9c18-e4b775df3793","data":null,"timestamp":1608006787253}

modules

health

@Module({ imports: [HealthModule]})
export class CoreModule {}

const app = await NestFactory.create(CoreModule, { cors: true });

decorator

User

@Controller('demo')
export class DemoController {
  @Get('user')
  @HttpCode(HttpStatus.OK)
  async index(@Req() req, @User() user) {
    return req['user'] ==== user ? user : null;
  }

IP

@Controller('demo')
export class DemoController {
  @Get('ip')
  @HttpCode(HttpStatus.OK)
  async index(@IP() ip) {
    return ip;
  }

Headers

@Controller('demo')
export class DemoController {
  @Get('headers')
  @HttpCode(HttpStatus.OK)
  async index(@Headers() headers) {
    return headers;
  }

interceptors

RequestIdInterceptor

const app = await NestFactory.create(CoreModule, { cors: true });
app.useGlobalInterceptors(new RequestIdInterceptor(logger));

// or
app.useGlobalInterceptors(new RequestIdInterceptor<SimpleLogger>(logger));

log

[Init Request ID] [GET] /demo/dto?test=1 ==> [bf852b17-93c6-4663-8bd4-1c00453687f8]

LoggerInterceptor

const app = await NestFactory.create(CoreModule, { cors: true });
app.useGlobalInterceptors(new LoggerInterceptor(logger));
// or
app.useGlobalInterceptors(new LoggerInterceptor<SimpleLogger>(logger));

log

[Success] [DemoController] [GET] /demo/dto?test=1 ==> [200] 
[Request] [ID]   bf852b17-93c6-4663-8bd4-1c00453687f8 
[Request] [Query]   {"test":"1"} 
[Request] [Body]    {} 
[Request] [Headers] {"accept":"application/json, text/plain, */*","user-agent":"axios/0.21.0","host":"localhost:6666","connection":"close","x-api-request-id":"bf852b17-93c6-4663-8bd4-1c00453687f8"} 
[Response] [Detail]  {"code":0,"timestamp":1608006787263,"message":"Request Success","requestId":"bf852b17-93c6-4663-8bd4-1c00453687f8","data":{"test":"1"}}

FormatInterceptor

/**
 * Instantiation FormatInterceptor
 *
 * @param options `StatusOptions`
 * @param options.codes `StatusCodes` response http exception status code.
 * @param options.status `StatusMaps` response status.
 * @param options.language `'zh' | 'en'`
 */
const app = await NestFactory.create(CoreModule, { cors: true });

// Use the default configuration
app.useGlobalInterceptors(new FormatInterceptor());

// Custom your `statusCodes` `statusMaps`
const options = { statusCodes, statusMaps, language: ('en' as const) };
app.useGlobalInterceptors(new FormatInterceptor(options));

swagger

upload

export const ApiUpload = (fileName = 'file'): MethodDecorator => (
  target: any,
  propertyKey: string,
  descriptor: PropertyDescriptor,
) => {
  ApiBody({
    type: 'multipart/form-data',
    required: true,
    schema: {
      type: 'object',
      properties: {
        [fileName]: {
          type: 'array',
          items: {
            type: 'string',
            format: 'binary',
          },
        },
      },
    },
  })(target, propertyKey, descriptor);
};