Javascript

Nest FINAL release is here! Node.js framework built on top of TypeScript

Nest is a powerful web framework for Node.js, which helps you effortlessly build efficient, scalable applications. It uses modern JavaScript, is built with TypeScript and combines best concepts of both OOP (Object Oriented Progamming) and FP (Functional Programming).

It is not just another framework. You do not have to wait for a large community, because Nest is built with awesome, popular well-known libraries – Express and socket.io! It means, that you can quickly start using framework without worrying about a third party plugins.

Core Concept

The core concept of Nest is to provide an architecture, which helps developers to accomplish maximum separation of layers and increase abstraction in their applications.

Installation

Git:


$ git clone https://github.com/kamilmysliwiec/nest-typescript-starter.git projectname
$ cd projectname
$ npm install
$ npm run start

NPM:


$ npm i --save @nestjs/core @nestjs/common @nestjs/microservices @nestjs/websockets @nestjs/testing reflect-metadata rxjs

Setup Application

Nest is built with features from both ES6 and ES7 (decorators, async / await). It means, that the easiest way to start adventure with it is to use Babel or TypeScript.

In this article I will use TypeScript (it is not required!) and I recommend everyone to choose this way too. Sample tsconfig.json file:


{
  "compilerOptions": {
    "module": "commonjs",
    "declaration": false,
    "noImplicitAny": false,
    "noLib": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es6"
  },
  "exclude": [
    "node_modules"
  ]
}

Remember that emitDecoratorMetadata and experimentalDecorators properties have to be set to true.

So let’s start from scratch. Firstly, we have to create entry module of our application (app.module.ts):


import { Module } from '@nestjs/common';

@Module({})
export class ApplicationModule {}

At this moment module metadata is empty ({}), because we only want to run application (we do not have any controlles or components right now).

Second step – make file index.ts (or whatever) and use NestFactory to create Nest application instance based on our module class.


import { NestFactory } from '@nestjs/core';
import { ApplicationModule } from './app.module';

const app = NestFactory.create(ApplicationModule);
app.listen(3000, () => console.log('Application is listening on port 3000'));

That’s all.

Express instance

If you want to have a full control of express instance lifecycle, you can simply pass already created object as a second argument of NestFactory.create() method, just like that:


import express from 'express';
import { NestFactory } from '@nestjs/core';
import { ApplicationModule } from './modules/app.module';

const instance = express();
const app = NestFactory.create(ApplicationModule, instance);
app.listen(3000, () => console.log('Application is listening on port 3000'));

It means, that you can directly add some custom configuration (e.g. setup some plugins such as morgan or body-parser).

First Controller

The Controllers layer is responsible for handling incoming HTTP requests. In Nest, Controller is a simple class with @Controller() decorator.

Controllers_1

In previuos section we set up entry point for an application. Now, let’s build our first endpoint /users:


import { Controller, Get, Post } from '@nestjs/common';

@Controller()
export class UsersController {
    @Get('users')
    getAllUsers() {}

    @Get('users/:id')
    getUser() {}

    @Post('users')
    addUser() {}
}

As you can guess, we created an endpoint with 3 different paths:


GET: users
GET: users/:id 
POST: users

Is it necessary to repeat ‚users’ in each path? Nope.

Nest allows us to pass additional metadata to @Controller() decorator – path, which is a prefix for each route. Let’s rewrite our controller:


@Controller('users')
export class UsersController {
    @Get()
    getAllUsers(req, res, next) {}

    @Get('/:id')
    getUser(req, res, next) {}

    @Post()
    addUser(req, res, next) {}
}

As you can see, methods in Nest controllers have the same list of arguments and behaviour as a simple routes in Express.

If you want to learn more about req (request), res (response) and next you should read short Routing Documentation. In Nest, they work equivalently.

But there is a one important difference. Nest provides a set of custom decorators, which you can use to mark arguments.

Nest Express
@Request() req
@Response() res
@Next() next
@Session() req.session
@Param(param?: string) req.params[param]
@Body(param?: string) req.body[param]
@Query(param?: string) req.query[param]
@Headers(param?: string) req.headers[param]

This is how you can use them:


@Get('/:id')
public async getUser(@Response() res, @Param('id') id) {
    const user = await this.usersService.getUser(id);
    res.status(HttpStatus.OK).json(user);
}

Remember to import decorators at the beginning of a file:


import { Response, Param } from '@nestjs/common';

UsersController is ready to use, but our module doesn’t know about it yet. Let’s open ApplicationModule and add some metadata.


import { Module } from '@nestjs/common';
import { UsersController } from "./users.controller";

@Module({
    controllers: [ UsersController ]
})
export class ApplicationModule {}

As you can see – we only have to insert our controller into controllers array. It’s everything.

Components

Almost everything is a component – Service, Repository, Provider etc. and they might be injected to controllers or to another component by constructor.

Components_1

In previous section, we built a simple controller – UsersController. This controller has an access to our data (I know, it’s a fake data, but it doesn’t really matter here). It’s not a good solution. Our controllers should only handle HTTP requests and delegate more complex tasks to services. This is why we are going to create UsersService component.

In real world, UsersService should call appropriate method from persistence layer e.g. UsersRepository component. We don’t have any kind of database, so again – we will use fake data.


import { Component } from '@nestjs/common';
import { HttpException } from '@nestjs/core';

@Component()
export class UsersService {
    private users = [
        { id: 1, name: "John Doe" },
        { id: 2, name: "Alice Caeiro" },
        { id: 3, name: "Who Knows" },
    ];
    getAllUsers() {
        return Promise.resolve(this.users);
    }
    getUser(id: number) {
        const user = this.users.find((user) => user.id === id);
        if (!user) {
            throw new HttpException("User not found", 404);
        }
        return Promise.resolve(user);
    }
    addUser(user) {
        this.users.push(user);
        return Promise.resolve();
    }
}

Nest Component is a simple class, with @Component() annotation.

As might be seen in getUser() method we used HttpException. It is a Nest built-in Exception, which takes two parameters – error message and status code. It is a good practice to create domain exceptions, which should extend HttpException (more about it in „Error Handling” section).

Our service is prepared, let’s use it in UsersController.


@Controller('users')
export class UsersController {
    constructor(private usersService: UsersService) {}

    @Get()
    getAllUsers(@Response req) {
        this.usersService.getAllUsers()
            .then((users) => res.status(HttpStatus.OK).json(users));
    }

    @Get('/:id')
    getUser(@Response() res, @Param('id') id) {
        this.usersService.getUser(+id)
            .then((user) => res.status(HttpStatus.OK).json(user));
    }

    @Post()
    addUser(@Response() res, @Body('user') user) {
        this.usersService.addUser(req.body.user)
            .then((msg) => res.status(HttpStatus.CREATED).json(msg));
    }
}

As shown, UsersService will be injected into constructor.

It is incredibly easy to manage dependencies with TypeScript, because Nest will recognize your dependencies just by type! So this:


constructor(private usersService: UsersService)

Is everything what you have to do. There is one important thing to know — you must have emitDecoratorMetadata option set to true in your tsconfig.json.

If you are not TypeScript enthusiast and you work with plain JavaScript, you have to do it in this way:


import { Dependencies, Controller, Get, Post, Response, Param, Body, HttpStatus } from '@nestjs/common';

@Controller('users')
@Dependencies(UsersService)
export class UsersController {
    constructor(usersService) {
        this.usersService = usersService;
    }

    @Get()
    getAllUsers(@Response() res) {
        this.usersService.getAllUsers()
            .then((users) => res.status(HttpStatus.OK).json(users));
    }

    @Get('/:id')
    getUser(@Response() res, @Param('id') id) {
        this.usersService.getUser(+id)
            .then((user) => res.status(HttpStatus.OK).json(user));
    }

    @Post()
    addUser(@Response() res, @Body('user') user) {
        this.usersService.addUser(user)
            .then((msg) => res.status(HttpStatus.CREATED).json(msg));
    }
}

Simple, right?

In this moment, application will not even start working.

Why? Because Nest doesn’t know anything about UsersService. This component is not a part of ApplicationModule yet. We have to add it there:


import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

@Module({
    controllers: [ UsersController ],
    components: [ UsersService ],
})
export class ApplicationModule {}

That’s it! Now, our application will run, but still one of routes doesn’t work properlyaddUser. Why? Because we are trying to extract request body (req.body.user) without body-parser express middleware. As you should already know, it is possible to pass express instance as a second argument of NestFactory.create() method.

Let’s install plugin:


$ npm install --save body-parser

Then setup it in our express instance.


import express from 'express';
import * as bodyParser from 'body-parser';
import { NestFactory } from '@nestjs/common';
import { ApplicationModule } from './modules/app.module';

const instance = express();
instance.use(bodyParser.json());

const app = NestFactory.create(ApplicationModule, instance);
app.listen(3000, () => console.log('Application is listening on port 3000'));

Async / await

Nest is compatible with async / await feature from ES7, so we can quickly rewrite our UsersController:


@Controller('users')
export class UsersController {
    constructor(private usersService: UsersService) {}

    @Get()
    async getAllUsers(@Response() res) {
        const users = await this.usersService.getAllUsers();
        res.status(HttpStatus.OK).json(users);
    }
r
    @Get('/:id')
    async getUser(@Response() res, @Param('id') id) {
        const user = await this.usersService.getUser(+id);
        res.status(HttpStatus.OK).json(user);
    }

    @Post()
    async addUser(@Response() res, @Body('user') user) {
        const msg = await this.usersService.getUser(user);
        res.status(HttpStatus.CREATED).json(msg);
    }
}

Looks better right? There you can read more about async / await.

Modules

Module is a class with @Module({}) decorator. This decorator provides metadata, which framework uses to organize application structure.

Modules_1

Right now, it is our ApplicationModule:


import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

@Module({
    controllers: [ UsersController ],
    components: [ UsersService ],
})
export class ApplicationModule {}

By default, modules encapsulate each dependency. It means, that it is not possible to use its components / controllers outside module.

Each module can also import another modules. In fact, you should think about Nest Modules as a tree of modules.

Let’s move UsersController and UsersService to UsersModule. Simply create new file e.g. users.module.ts with below content:


import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

@Module({
    controllers: [ UsersController ],
    components: [ UsersService ],
})
export class UsersModule {}

Then import UsersModule into ApplicationModule (our main application module):


import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module';

@Module({
    modules: [ UsersModule ]
})
export class ApplicationModule {}

It’s everything.

As might be seen, with Nest you can naturally split your code into separated and reusable modules!

Dependency Injection

Module can easily inject components, which belongs to it:


@Module({
    controllers: [ UsersController ],
    components: [ UsersService, ChatGateway ],
})
export class UsersModule implements NestModule {
    constructor(private usersService: UsersService) {}
}

Furthermore, components also can inject modules:


export class UsersController {
    constructor(private module: UsersModule) {}
}

Middlewares

Middleware is a function, which is called before route handler. Middleware functions have access to request and response objects, so they can modify them. They can also be something like a barrier – if middleware function does not call next(), the request will never be handled by route handler.

Middlewares_1

Let’s build a dummy authorization middleware (for explanation purposes – just by username). We will use X-Access-Token HTTP header to provide username (weird idea, but it doesn’t matter here).


import { UsersService } from './users.service';
import { HttpException } from '@nestjs/core';
import { Middleware, NestMiddleware } from '@nestjs/common';

@Middleware()
export class AuthMiddleware implements NestMiddleware {
    constructor(private usersService: UsersService) {}

    resolve() {
        return (req, res, next) => {
            const userName = req.headers["x-access-token"];
            const users = this.usersService.getUsers();

            const user = users.find((user) => user.name === userName);
            if (!user) {
                throw new HttpException('User not found.', 401);
            }
            req.user = user;
            next();
        }
    }
}

Some facts about middlewares:

  • you should use @Middleware() annotation to tell Nest, that this class is a middleware,
  • you can use NestMiddleware interface, which forces on you to implement resolve() method,
  • middlewares (same as components) can inject dependencies through their constructor (dependencies have to be a part of module),
  • middlewares must have resolve() method, which must return another function (higher order function). Why? Because there is a lot of third-party, ready to use express middlewares, which you could simply – thanks to this solution – use in Nest.

Okey, we already have prepared middleware, but we are not using it anywhere. Let’s set it up:


import { Module, MiddlewaresConsumer } from '@nestjs/common';

@Module({
    controllers: [ UsersController ],
    components: [ UsersService ],
    exports: [ UsersService ],
})
export class UsersModule {
    configure(consumer: MiddlewaresConsumer) {
        consumer.apply(AuthMiddleware).forRoutes(UsersController);
    }
}

As shown, Modules can have additional method – configure(). This method receives as a parameter MiddlewaresConsumer, an object, which helps us to configure middlewares.

This object has apply() method, which receives infinite count of middlewares (this method uses spread operator, so it is possible to pass multiple classes separated by comma). apply() method returns object, which has two methods:

  • forRoutes() – we use this method to pass infinite count of Controllers or objects (with path and method properties) separated by comma,
  • with() – we use this method to pass custom arguments to resolve()method of middleware.

How does it works?

When you pass UsersController in forRoutes method, Nest will setup middleware for each route in controller:


GET: users
GET: users/:id 
POST: users

But it is also possible to directly define for which path middleware should be used, just like that:


consumer.apply(AuthMiddleware).forRoutes({
    path: '*', method: RequestMethod.ALL 
});

Chaining

You can simply chain apply() calls:


consumer.apply(AuthMiddleware, PassportMidleware)
    .forRoutes(UsersController, OrdersController, ClientController);
    .apply(...)
    .forRoutes(...);

Ordering

Middlewares are called in the same order as they are placed in array. Middlewares configured in sub-module are called after the parent module configuration.

Real-time applications with Gateways

There are special components in Nest called Gateways. Gateways help us to create real-time web apps. They are some kind of encapsulated socket.io features adjusted to framework architecture.

Gateways_1

Gateway is a Component, so it can inject dependencies through constructor. Gateway also can be injected into another component.


import { WebSocketGateway } from '@nestjs/websockets';

@WebSocketGateway()
export class UsersGateway {}

By default – server runs on port 80 and with default namespace. We can easily change those settings:


@WebSocketGateway({ port: 81, namespace: 'users' })

Of course – server will run only if UsersGateway component is listed in module components array, so we have to place it there:


@Module({
    controllers: [ UsersController ],
    components: [ UsersService, UsersGateway ],
    exports: [ UsersService ],
})

By the way, there are three useful events of Gateway:

  • afterInit, which gets as an argument native server socket.io object,
  • handleConnection and handleDisconnect, which gets as an argument native client socket.io object.

There are special interfaces, which helps to manage lifecycle hooks OnGatewayInit, OnGatewayConnection and OnGatewayDisconnect.

What with messages?

In Gateway, we can simply subscribe to emitted messages:


import { WebSocketGateway, SubscribeMessage } from '@nestjs/websockets';

@WebSocketGateway({ port: 81, namespace: 'users' })
export class UsersGateway {
    @SubscribeMessage('drop')
    handleDropMessage(sender, data) {
        // sender is a native socket.io client object
    }
}

And from client side:


import * as io from 'socket.io-client';
const socket = io('http://URL:PORT/');
socket.emit('drop', { msg: 'test' });

@WebSocketServer()

If you want to assign to chosen property socket.io native server instance, you could simply decorate it with @WebSocketServer() decorator.


import { WebSocketGateway, WebSocketServer } from '@nestjs/websockets';

@WebSocketGateway({ port: 81, namespace: 'users' })
export class UsersGateway {
    @WebSocketServer() server;

    @SubscribeMessage('drop')
    handleDropMessage(sender, data) {
        // sender is a native socket.io client object
    }
}

Value will be assigned after server initialization.

Gateway Middlewares

Gateway middlewares works almost same as route middlewares. Middleware is a function, which is called before gateway message subscriber. Gateways middleware functions have access to native socket object. They can be something like a barrier — if middleware function does not call next(), the message will never be handled by subscriber.

Example:


@Middleware()
export class AuthMiddleware implements GatewayMiddleware {
    public resolve(): (socket, next) => void {
        return (socket, next) => {
            console.log('Authorization...');
            next();
        };
    }
}

Some facts about gateway middlewares:

  • you should use @Middleware() annotation to tell Nest, that this class is a middleware,
  • you can use GatewayMiddleware interface, which forces on you to implement resolve() method,
  • middlewares (same as components) can inject dependencies through their constructor (dependencies have to be a part of module),
  • middlewares must have resolve() method, which must return another function (higher order function).

Okey, we already have prepared middleware, but we are not using it anywhere. Let’s set it up:


@WebSocketGateway({
    port: 2000,
    middlewares: [ ChatMiddleware ],
})
export class ChatGateway {}

As shown @WebSocketGateway() accepts additional metadata property – middlewares, which is an array of middlewares. Those middlewares will be called before message handlers.

Reactive Streams

As you already know, Nest Gateway is a simple component, which can be injected into another components. This feature gives us possibility to choose how we are going to react on messages.

Of course – we can just inject components to Gateway and call their appropriate methods, when it is necessary.

But there is another solution – Gateway Reactive Streams. You can read more about them here.

Microservices Support

It is unbelievably simple to transform Nest application into Nest microservice.

Take a look – this is how you create web application:


const app = NestFactory.create(ApplicationModule);
app.listen(3000, () => console.log('Application is listening on port 3000'));

Now, switch it to a microservice:


const app = NestFactory.createMicroservice(ApplicationModule, { port: 3000 });
app.listen() => console.log('Microservice is listening on port 3000'));

It’s everything!

Communication via TCP

Microservices_1

By default Nest microservice is listening for messages via TCP protocol. It means that right now @RequestMapping() (and @Post(), @Get() etc. too) will not be useful, because it is mapping HTTP requests. So, how microservice will recognize messages? Just by patterns.

What is pattern? It is nothing special. It could be an object, string or even number (but it is not a good idea).

Let’s create MathController:


import { MessagePattern } from '@nestjs/microservices';

@Controller()
export class MathController {
    @MessagePattern({ cmd: 'add' })
    add(data, respond) {
        const numbers = data || [];
        respond(null, numbers.reduce((a, b) => a + b));
    }
}

As you might seen – if you want to create message handler, you have to decorate it wih @MessagePattern(pattern). In this example, I chose { cmd: 'add' } as a pattern.

The handler method receives two arguments:

  • data, which is a variable with data sent from another microservice (or just web application),
  • respond a function which accepts two arguments (error, response).

Client

You already know how to listen for messages. Now, let’s check how to send them from another microservice or web application.

Before you can start, Nest has to know, where you are exactly going to send messages. It’s easy – you only have to create @Client object.


import { Controller } from '@nestjs/common';
import { Client, ClientProxy, Transport } from '@nestjs/microservices';

@Controller()
export class ClientController {
    @Client({ transport: Transport.TCP, port: 5667 })
    client: ClientProxy;
}

@Client() decorator receives object as a parameter. This object can have 3 properties:

  • transport – with this you can decide which method you are going to use – TCP or Redis (TCP by default),
  • url – only for Redis purposes (default – redis://localhost:6379),
  • port (default 3000).

Use client

Let’s create custom endpoint to test our communication.


import { Controller, Get } from '@nestjs/common';
import { Client, ClientProxy, Transport } from '@nestjs/microservices';

@Controller()
export class ClientController {
    @Client({ transport: Transport.TCP, port: 5667 })
    client: ClientProxy;

    @Get('client')
    sendMessage(req, res) {
        const pattern = { command: 'add' };
        const data = [ 1, 2, 3, 4, 5 ];

        this.client.send(pattern, data)
            .catch((err) => Observable.empty())
            .subscribe((result) => res.status(200).json({ result }));
    }
}

As you might seen, in order to send message you have to use send method, which receives message pattern and data as an arguments. This method returns an Observable from Rxjs package.

It is very important feature, because reactive Observables provide set of amazing operators to deal with, e.g. combine, zip, retryWhen, timeout and more…

Of course, if you want to use Promises instead of Observables, you could simply use toPromise() method.

That’s all.

Now, when someone will make /test request (GET), that’s how response should looks like (if both microservice and web app are available):


{
    "result": 15
}

Redis

There is another way to work with Nest microservices. Instead of direct TCP communication, we could use amazing Redis feature – publish / subscribe.

Redis_1

Of course before you can use it, it is obligatory to install Redis.

Create Redis microservice

To create Redis Microservice, you have to pass additional configuration in NestFactory.createMicroservice() method.


const app = NestFactory.createMicroservice(
    MicroserviceModule,
    {
        transport: Transport.REDIS,
        url: 'redis://localhost:6379'
    }
);
app.listen(() => console.log('Microservice listen on port:', 5667 ));

And that’s all. Now your microservice will subscribe to messages published via Redis. The rest works same – patterns, error handling, etc.

Redis Client

Now, let’s see how to create client. Previously, your client instance configuration looks like that:


@Client({ transport: Transport.TCP, port: 5667 })
client: ClientProxy;

We want to use Redis instead of TCP, so we have to change those settings:


@Client({ transport: Transport.REDIS, url: 'redis://localhost:6379' })
client: ClientProxy;

Easy, right? That’s all. Other functionalities works same as in TCP communication.

Shared Module

Nest Modules can export their components. It means, that we can easily share component instance between them.

The best way to share an instance between two or more modules is to create Shared Module.

Shared_Module_1

For example – if we want to share ChatGateway component across entire application, we could do it in this way:


import { Module, Shared } from '@nestjs/common';

@Shared()
@Module({
    components: [ ChatGateway ],
    exports: [ ChatGateway ]
})
export class SharedModule {}

Then, we only have to import this module into another modules, which should share component instance:


@Module({
    modules: [ SharedModule ]
})
export class FeatureModule {}

That’s all.

Notice! It is also possible to directly define scope of Shared Module. More details.

Dependency Injection

Dependency Injection is a strong mechanism, which helps us easily manage dependencies of our classes. It is very popular pattern in strongly typed languages like C# and Java.

In Node.js it is not such important to use those kind of features, because we already have amazing module loading system and e.g. sharing instance between files is effortless.

The module loading system is sufficient for small and medium size applications. When amount of code grows, it is harder and harder to smoothly organize dependencies between layers. Someday everything may just blow up.

giphy

It is also less intuitive than DI by constructor.

This is the reason, why Nest has its own DI system.

Custom components

You have already learnt, that it is incredibly easy to add component to chosen module:


@Module({
    controllers: [ UsersController ],
    components: [ UsersService ]
})

But there is some other scenarios, which Nest allows you to take advantages of.

Use value:


const value = {};
@Module({
    controllers: [ UsersController ],
    components: [
        { provide: UsersService, useValue: value }
    ],
})

When:

  • you want to use specific value. Now, in this module Nest will associate value with UsersService metatype,
  • you want to use test doubles (unit testing).

Use class:


@Component()
class CustomUsersService {}

@Module({
    controllers: [ UsersController ],
    components: [
        { provide: UsersService, useClass: CustomUsersService }
    ],
})

When:

  • you want to use chosen, more specific class only in this module.

Use factory:


@Module({
    controllers: [ UsersController ],
    components: [
        ChatService,
        {
            provide: UsersService,
            useFactory: (chatService) => {
                return Observable.of('value');
            },
            inject: [ ChatService ]
        }
    ],
})

When:

  • you want to provide a value, which has to be calculated using other components (or custom packages features),
  • you want to provide async value (just return Observable or Promise), e.g. database connection.

Remember:

  • if you want to use components from module, you have to pass them in inject array. Nest will pass instances as a arguments of factory in the same order.

Custom providers


@Module({
    controllers: [ UsersController ],
    components: [
        { provide: 'isProductionMode', useValue: false }
    ],
})

When:

  • you want to provide value with a chosen key.

Remember:

  • it is possible to use each types useValue, useClass and useFactory.

How to use?

To inject custom provided component / value with chosen key, you have to tell Nest about it, just like that:


import { Component, Inject } from '@nestjs/common';

@Component()
class SampleComponent {
    constructor(@Inject('isProductionMode') isProductionMode: boolean) {
        console.log(isProductionMode); // false
    }
}

ModuleRef

Sometimes you might want to directly get component instance from module reference. It not a big thing with Nest – just inject ModuleRef in your class:


export class UsersController {
    constructor(
        private usersService: UsersService,
        private moduleRef: ModuleRef) {}
}

ModuleRef provides one method:

  • get<T>(key), which returns instance for equivalent key (mainly metatype). Example moduleRef.get<UsersService>(UsersService) returns instance of UsersService component from current module.

Example:


moduleRef.get<UsersService>(UsersService)

It returns instance of UsersService component from current module.

Testing

Nest gives you a set of test utilities, which boost application testing process. There are two different approaches to test your components and controllers – isolated tests or with dedicated Nest test utilities.

Isolated Tests

Both Nest controllers and components are a simple JavaScript classes. Itmeans, that you could easily create them by yourself:


const instance = new SimpleComponent();

If your class has any dependency, you could use test doubles, for example from such libraries as Jasmine or Sinon:


const stub = sinon.createStubInstance(DependencyComponent);
const instance = new SimpleComponent(stub);

Nest Test Utilities

The another way to test your applications building block is to use dedicated Nest Test Utilities.

Those Test Utilities are placed in static Test class (@nestjs/testing module).


import { Test } from '@nestjs/testing';

This class provide two methods:

  • createTestingModule(metadata: ModuleMetadata), which receives as an parameter simple module metadata (the same as Module() class). This method creates a Test Module (the same as in real Nest Application) and stores it in memory.
  • get<T>(metatype: Metatype<T>), which returns instance of chosen (metatype passed as parameter) controller / component (or null if it is not a part of module).

Example:


Test.createTestingModule({
    controllers: [ UsersController ],
    components: [ UsersService ]
});
const usersService = Test.get<UsersService>(UsersService);

Mocks, spies, stubs

Sometimes you might not want to use a real instance of component / controller. Instead of this – you can use test doubles or custom values / objects.


const mock = {};
Test.createTestingModule({
    controllers: [ UsersController ],
    components: [
        { provide: UsersService, useValue: mock }
    ]
});
const usersService = Test.get<UsersService>(UsersService); // mock

Exception Filters

With Nest you can move exception handling logic to special classes called Exception Filters.

How it works?

Let’s take a look at following code:


@Get('/:id')
public async getUser(@Response() res, @Param('id') id) {
    const user = await this.usersService.getUser(id);
    res.status(HttpStatus.OK).json(user);
}

Imagine that usersService.getUser(id) method could throws UserNotFoundException. What’s now? We have to catch an exception in route handler:


@Get('/:id')
public async getUser(@Response() res, @Param('id') id) {
    try {
        const user = await this.usersService.getUser(id);
        res.status(HttpStatus.OK).json(user);
    }
    catch(exception) {
        res.status(HttpStatus.NOT_FOUND).send();
    }
}

To sum up, we have to add try...catch blocks to each route handler, where an exception may occur. Is there another way? Yes – Exception Filters.

Let’s create NotFoundExceptionFilter:


import { Catch, ExceptionFilter, HttpStatus } from '@nestjs/common';

export class UserNotFoundException {}
export class OrderNotFoundException {}

@Catch(UserNotFoundException, OrderNotFoundException)
export class NotFoundExceptionFilter implements ExceptionFilter {
    catch(exception, response) {
        response.status(HttpStatus.NOT_FOUND).send();
    }
}

Now, we only have to tell our Controller to use this filter:


import { ExceptionFilters } from '@nestjs/common';

@ExceptionFilters(NotFoundExceptionFilter)
export class UsersController {}

So if usersService.getUser(id) throws UserNotFoundException, NotFoundExceptionFilter will catch it.

More exception filters

Each controller may has infinite count of exception filters (just separate them by comma).


@ExceptionFilters(NotFoundExceptionFilter, AnotherExceptionFilter)

Dependency Injection

Exception filters works same as Components, so they can inject dependencies through constructor.

HttpException

Notice: It is mainly for REST applications.

Nest has error handling layer, which catches all unhandled exceptions.

If – somewhere – in your application, you will throw an Exception, which is not HttpException (or inherited one), Nest will handle it and return to user below json object (500 status code):


{
    "message": "Unkown exception"
}

Exception Hierarchy

In your application, you should create your own Exceptions Hierarchy. All HTTP exceptions should inherit from built-in HttpException.

For example, you can create NotFoundException and UserNotFoundException classes:


import { HttpException } from '@nestjs/core';

export class NotFoundException extends HttpException {
    constructor(msg: string | object) {
        super(msg, 404);
    }
}

export class UserNotFoundException extends NotFoundException {
    constructor() {
        super('User not found.');
    }
}

Then – if you somewhere in your application throw UserNotFoundException, Nest will response to user with status code 404 and above json object:


{
    "message": "User not found."
}

It allows you to focus on logic and make your code much easier to read.

Useful references

GitHub / Download

Documentation

NPM