Announcing NestJS 7: What’s New ?

Kamil Mysliwiec | Trilon Consulting
Kamil Mysliwiec

Today I am excited to announce the official release of NestJS 7. This is a major release spanning the entire platform, including the framework, numerous changes to the @nestjs/graphql package, CLI improvements, and updated documentation.

In case you're not familiar with NestJS, it is a TypeScript Node.js framework that helps you build enterprise-grade efficient and scalable Node.js applications.

Photo by Stéphane Mingot

Last year was great for our community. In 2019, Nest has been recognised as the fastest-growing Node.js technology in the world. We've also made it to the TOP 20 GitHub repositories on the whole globe, and, according to NPM metrics, experienced an almost 400% growth in number of downloads on NPM, and thus becoming one of the most popular Node.js libraries with roughly 1 million of downloads each month! 2019 was amazing and we expect 2020 to be even better for the whole ecosystem!

What’s new?

This release brings lots of great features and long-awaited improvements. There are far too many to list here, but let’s take a high-level look at some of the most exciting ones.

GraphQL ❤️ TypeScript

In the version 6 major release of NestJS (announced here), we introduced the code first approach as a compatibility layer between the amazing type-graphql package and the official @nestjs/graphql module. This allowed us to solve types redundancy problems by automatically generating GraphQL SDL from TypeScript metadata using decorators.

However, despite the numerous new opportunities that this integration has brought, we have faced many challenges that did not seem easily solvable down the road.

  • The integration required developers to mix decorators coming from two different libraries. If you've messed up the imports, all your resolvers would stop injecting dependencies through constructor (all of them would be equal to undefined). Thus, developers reported many bugs and issues, assuming that the integration doesn't work at all.

  • To generate a schema, type-graphql generates resolve function for each field. However, Nest has its own DI system that links dependencies and instantiates classes (in this case, providers), which methods are later being bounded to GraphQL fields. Hence, it led to unnecessary memory allocations.

  • Lastly, the code first approach requires using many additional decorators to define input types, args, etc. Initially, we decided to simply link to the external library documentation. However, the API of decorators which wrapped external decorators was somewhat different (because we must support schema first approach as well). We also didn't want to duplicate the documentation in the NestJS documentation because maintaining it would become impossible in the long run (adjusting to API changes, etc.).

So what did we do?

In order to future-proof the library to meet the needs of the community, we needed to reimplement all the features from scratch due to a lack of predictability and flexibility while dealing with the third party library.

To avoid lots of breaking changes, we did our best to make sure that the public API IS backwards-compatible.

Therefore, with a simple update: (search & replace) all the type-graphql imports to use @nestjs/graphql, and that's it. 🎊

import { Field, Int, ObjectType } from '@nestjs/graphql';
import { Post } from './post';

@ObjectType()
export class Author {
  @Field(type => Int)
  id: number;

  @Field({ nullable: true })
  firstName?: string;

  @Field({ nullable: true })
  lastName?: string;

  @Field(type => [Post])
  posts: Post[];
}

Learn more about the code first approach here.

NestJS GraphQL Plugin

In addition, switching to our own Typescript & GraphQL implementation, allowed us to create a plugin (similar to the @nestjs/swagger announced here).

To reduce the amount of boilerplate code required, Nest now provides a new GraphQL plugin (for code first applications) that enhances the TypeScript compilation process.

Hint This plugin is also opt-in. If you prefer, you can declare all decorators manually, or only specific decorators where you need them.

The new GraphQL plugin will automatically:

  • annotate all input object (@InputObject), object type (@ObjectType) and args (@Args) classes properties with @Field decorator unless @HideField is used
  • set the nullable property depending on the question mark (e.g. name?: string will set nullable: true)
  • set the type property depending on the type (supports arrays as well)

Therefore, the example shown above can be rewritten as follows:

import { Field, Int, ObjectType } from '@nestjs/graphql';
import { Post } from './post';

@ObjectType()
export class Author {
  @Field(type => Int)
  id: number;
  firstName?: string;
  lastName?: string;
  posts: Post[];
}

The plugin adds appropriate decorators on the fly based on the Abstract Syntax Tree.

TIP: You no longer have to struggle with @Field boilerplate decorators scattered throughout the entire project. They will be added automatically.

Learn how to enable the plugin here.

Flexible Custom Decorators

The custom decorators API has been unified for all types of applications. Now, whether you're creating a GraphQL application or a REST API, the factory passed into the createParamDecorator() function will take the ExecutionContext (read more here) object as a second argument.

import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const User = createParamDecorator(
  (data: unknown, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    return request.user;
  },
);

Now, to determine the type of application that our decorator is currently evaluated, use the getType() method:

const type = host.getType();
if (type === 'http') {
  // HTTP application
} else if (type === 'rpc') {
  // Microservice
}

Improved Microservices

To enable the request-response message style, Nest creates two logical channels - one is responsible for transferring the data while the other waits for incoming responses.

For some underlying transports, such as NATS, this dual-channel support is provided out-of-the-box. For others, Nest compensates by manually creating separate channels.

Let's say that we have a single message handler @MessagePattern('getUsers'). In the past, Nest built two channels from this pattern: getUsers_ack (for requests) and getUsers_res (for responses). With version 7, this naming scheme changes. Now Nest will build getUsers channel (for requests) and getUsers.reply (for responses) instead. Also, specifically for the MQTT transport strategy, the response channel would be getUsers/reply.

This change simplifies the integration with external systems, existing legacy applications, and also, allows avoiding clashes with wildcard subscriptions available in, for example, MQTT strategy.

Furthermore, the overall performance will improve. From now on, Nest will no longer send out redundant information as part of the message packets (in the request-response message style), hence, decreasing their size.

New Pipes

Nest v7 comes with 2 NEW pipes available out-of-the-box, respectively ParseBoolPipe and ParseArrayPipe (both exported from the @nestjs/common package).

While ParseBoolPipe is just another transformer pipe which along with the existing ParseIntPipe can implicitly transform & validate values based on the expected type (read more here), ParseArrayPipe is a solution for sending either unwrapped or serialized arrays through the network.

Basically, TypeScript does not store metadata about generics or interfaces, so when you use them in your DTOs (Data Transfer Objects), ValidationPipe may not be able to properly validate incoming data. For instance, the code below won't be correctly validated:

@Post()
createBulk(@Body() createUserDtos: CreateUserDto[]) {
  return 'This action adds new users';
}

Previously, to validate the array you had to create a dedicated class which contained a property that wraps the array. Now, you can simply use the ParseArrayPipe.

@Post()
createBulk(
  @Body(new ParseArrayPipe({ items: CreateUserDto }))
  createUserDtos: CreateUserDto[],
) {
  return 'This action adds new users';
}

In addition, the ParseArrayPipe may come in handy when parsing query parameters. Let's define the findByIds() method that returns users based on identifiers passed as query parameters.

@Get()
findByIds(
  @Query('id', new ParseArrayPipe({ items: Number, separator: ',' }))
  ids: number[],
) {
  return 'This action return users by ids';
}

And test this endpoint using cURL:

$ # GET /?ids=1,2,3
$ curl http://localhost:3000/?ids=1,2,3

The stringified ids query parameter (ids=1,2,3) will be automatically transformed to an array. In addition, each item will be validated and eventually, parsed to a number.

Implicit type conversion

With the auto-transformation option enabled (transform: true), the ValidationPipe will now perform conversion of primitive types. In the following example, the findOne() method takes one argument which represents an extracted id path parameter:

@Get(':id')
findOne(@Param('id') id: number) {
  console.log(typeof id === 'number'); // true
  return 'This action returns a user';
}

By default, every path parameter and query parameter comes over the network as a string. In the above example, we specified the id type as a number (in the method signature). Therefore, the ValidationPipe will try to automatically convert the string identifier to a number.

Documentation

Our official documentation has significant improvements to GraphQL section. We now cover most of features / functionalities you may need to get started with either schema first or code first approaches.

We strongly believe that this update will strongly improve the development experience. 🐈


Enterprise Consulting & Support

Our official NestJS Enterprise Consulting includes a broad range of services to empower your team.

We work alongside you to meet your deadlines while avoiding costly tech debt. Challenging issue? We've got you covered.

  • Providing technical guidance & architectural reviews
  • Mentoring team members
  • Addressing security & performance concerns
  • Performing in-depth code reviews
  • Long-term support (LTS) & upgrade assistance

Our goal is to help you get to market faster. Nest core team members will help you utilize best practices and choose the right strategy for unique goals. You can learn more on the enterprise.nestjs.com.

Official NestJS Courses

We've recently launched a new website dedicated for the Official NestJS courses 📸 recorded by NestJS core team members.

With these courses, you'll learn everything about NestJS from the basic principles, best-practices, tips & tricks, to advanced patterns, getting you ready to build NestJS applications at any scale. 🚀

Sign up for the Nest newsletter right now and stay up do date with all the latest news. Everyone who signed up will be notificed once pre-order starts.

Migration from Nest 6

In order to migrate your existing project, follow the guidelines that are available here. Also, make sure to get rid of all deprecation messages that may appear in your console.


Support the NestJS Project

Nest is an MIT-licensed open source project with its ongoing development made possible thanks to the support by the community and our sponsors. Thank you!

This framework is a result of the long days, sleepless nights, and busy weekends. And we fully rely on the goodness ❤️ of the people. If you want to join them, you can read more here.

T-Shirts and hoodies

If you enjoy using NestJS and you would like to donate to our Open Source work (have your cake 🍰 and eat it), we just launched the official NestJS store 👕 where you can buy hoodies, T-shirts, and accessories!


Thank you

To all backers, sponsors, contributors, and community, thank you once again! This product is for you. And this is only the beginning of the long 🚀 story.

Become a Backer or Sponsor to Nest by donating to our open collective. ❤

#NestJS
#NodeJS

Share this Post!

📬 Trilon Newsletter

Stay up to date with all the latest Articles & News!

More from the Trilon Blog .

Michael Hladky | Trilon Consulting
Michael Hladky

Dealing with Late Subscribers in RxJS

Learn several ways to handle incoming Rx values that arrive before a Subscription has happened.

Read More
Kamil Mysliwiec | Trilon Consulting
Kamil Mysliwiec

Announcing the Official NestJS Course

Announcing the Official NestJS Course - Learn all the fundamentals of NestJS in this hands-on 5+ hour course from the NestJS creator and core team members themselves!

Read More
Kamil Mysliwiec | Trilon Consulting
Kamil Mysliwiec

Introducing Mapped Types for NestJS

Learn about the new NestJS Mapped Types and how to use them to drastically reduce the amount of boilerplate code required.

Read More

What we do at Trilon .

At Trilon, our goal is to help elevate teams - giving them the push they need to truly succeed in today's ever-changing tech world.

Trilon - Consulting

Consulting .

Let us help take your Application to the next level - planning the next big steps, reviewing architecture, and brainstorming with the team to ensure you achieve your most ambitious goals!

Trilon - Development and Team Augmentation

Development .

Trilon can become part of your development process, making sure that you're building enterprise-grade, scalable applications with best-practices in mind, all while getting things done better and faster!

Trilon - Workshops on NestJS, Node, and other modern JavaScript topics

Workshops .

Have a Trilon team member come to YOU! Get your team up to speed with guided workshops on a huge variety of topics. Modern NodeJS (or NestJS) development, JavaScript frameworks, Reactive Programming, or anything in between! We've got you covered.

Trilon - Open-source contributors

Open-source .

We love open-source because we love giving back to the community! We help maintain & contribute to some of the largest open-source projects, and hope to always share our knowledge with the world!

Explore more

Write us a message .

Let's talk about how Trilon can help your next project get to the next level.

Rather send us an email? Write to:

hello@trilon.io
© 2019-2020 Trilon, Inc.