NestJS was first developed in January 2017.1, and the first official release was released in July 2017.5. It is an Express based backend framework developed in TypeScript. At the beginning of the design, it was mainly used to solve the architectural problems of developing Node.js applications. It was inspired by Angular. In this article, I’ll outline some of the highlights in NestJS.

Component container

NestJS uses a component container, where each component is decoupled from other components. When a component depends on another component, it needs to specify node dependencies to be used:

import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
import { OtherModule } from '.. /OtherModule';

@Module({
  imports: [OtherModule],
  controllers: [CatsController],
  providers: [CatsService],
})
export class CatsModule {}
Copy the code

Dependency Injection (DI)

Like Angular, it uses the dependency injection design pattern for development

When you use an object, the DI container already creates it for you, without having to manually instantiate it, for decoupling purposes:

// Create a service
@Inject(a)export class TestService {
  public find() {
    return 'hello world'; }}// Create a controller
@Controller(a)export class TestController {
  controller(
    private readonly testService: TestService
  ) {}
  
  @Get(a)public findInfo() {
    return this.testService.find()
  }
}
Copy the code

To make the TestController use the TestService service, write as provider when creating the Module:

@Module({
  controllers: [TestController],
  providers: [TestService],
})
export class TestModule {}
Copy the code

Of course, you can Inject any class with @Inject() into the Module for use by the Module’s Controller or Service.

The implementation behind this is based on Decorator + Reflect Metadata. See typescript-Reflect Metadata for more details.

Fine-grained Middleware

With Express, we use a variety of middleware, such as logging services, timeout interception, permission validation, and so on. In NestJS, Middleware functions are divided into Middleware, Filters, Pipes, Grards, and Interceptors.

For example, use Filters to catch errors thrown by processing applications:

@Catch(a)export class AllExceptionsFilter implements ExceptionFilter {
  catch(exception: any, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const request = ctx.getRequest();
    const status = exception.getStatus();

    // Something else to do, such as using logs

    response
      .status(status)
      .json({
        statusCode: status,
        timestamp: new Date().toISOString(), path: request.url, }); }}Copy the code

Use the interceptor to intercept response data and return it in the format {data: T} :

import { Injectable, NestInterceptor, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

export interface Response<T> {
  data: T;
}

@Injectable(a)export class TransformInterceptor<T>
  implements NestInterceptor<T, Response<T>> {
  intercept(
    context: ExecutionContext,
    call$: Observable<T>,
  ): Observable<Response<T>> {
    return call$.pipe(map(data= >({ data }))); }}Copy the code

Using Guards, return 401 when there is no ‘admin’ role:

import { ReflectMetadata } from '@nestjs/common';
export const Roles = (. roles:string[]) = > ReflectMetadata('roles', roles);

@Post(a)@Roles('admin')
async create(@Body() createCatDto: CreateCatDto) {
  this.catsService.create(createCatDto);
}
Copy the code

Data validation

Thanks to class-Validator and class-Transformer, validation of incoming parameters becomes very simple:

/ / create a Dto
export class ContentDto {
  @IsString()
  text: string
}

@Controller(a)export class TestController {
  controller(
    private readonly testService: TestService
  ) {}
  
  @Get(a)public findInfo(
    @Param() param: ContentDto     / / use
  ) {
    return this.testService.find()
  }
}
Copy the code

A 400 error occurs when text is not a string.

GraphQL

GraphQL, developed by Facebook, is considered a revolutionary API tool because it allows clients to specify the data they want in a request, rather than being pre-defined on the back end like traditional REST.

NestJS wraps Apollo Server to make it easier to use in NestJS.

When using Apollo Server in Express:

const express = require('express');
const { ApolloServer, gql } = require('apollo-server-express');

// Construct a schema, using GraphQL schema language
const typeDefs = gql` type Query { hello: String } `;

// Provide resolver functions for your schema fields
const resolvers = {
  Query: {
    hello: (a)= > 'Hello world! ',}};const server = new ApolloServer({ typeDefs, resolvers });

const app = express();
server.applyMiddleware({ app });

const port = 4000;

app.listen({ port }, () =>
  console.log(`Server ready at http://localhost:${port}${server.graphqlPath}`));Copy the code

Use it in NestJS:

// test.graphql
type Query {
  hello: string;
}


// test.resolver.ts
@Resolver(a)export class {
  @Query(a)public hello() {
    return 'Hello wolrd'; }}Copy the code

Using a Decorator also looks more TypeScript.

other

In addition to the above enumeration, NestJS implements microservice development, TypeORM, and Prisma features, which are not covered here.

reference

  • Learn more about typescript-Reflect Metadata
  • Egg VS NestJS
  • NestJS website