Eliminating Redundancy with NestJS CLI Plugins. Comments Introspection

Kamil Mysliwiec | Trilon Consulting
Kamil Mysliwiec

In this article, we'll be looking at the NestJS CLI Plugins and the newly added feature: Comments Introspection 🔎

Currently, NestJS provides two plugins useful for both: GraphQL code first applications (@nestjs/graphql), and REST APIs (@nestjs/swagger) that require interactive API documentation.

These plugins can drastically reduce the amount of boilerplate code required to build NestJS applications, speeding up our development, eliminating redundancy, and improving overall application maintainability.

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.


Introduction to CLI Plugins

TypeScript's metadata reflection system has several limitations which make it impossible to, for instance, determine what properties a class consists of, or how to recognize whether a given property is optional or required. However, some of these constraints can be addressed at compilation time.

NestJS CLI plugins enhance the TypeScript compilation process and can analyze types and comments ahead of time, storing collected metadata in private data structures which can be accessed at runtime.

Using CLI Plugins

To enable plugins, open up the nest-cli.json file (if you use Nest CLI) and add the following plugins configuration:

{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"plugins": ["@nestjs/swagger"]
// or "plugins": ["@nestjs/graphql"]
}
}

As you can see, the plugins property indicates what plugins must be loaded by Nest CLI during the compilation process - no additional steps are needed! From now on, Nest CLI will automatically run plugins as part of the build (when you run either nest build or nest start commands).

NOTE: If you don't use the CLI, you can find more instructions here: Swagger or GraphQL.

Introducing the Introspect Comments option

When defining Nest CLI plugins. You have the ability to pass in an options property to customize the behavior of the plugin, as follows:

{
"plugins": [
{
"name": "@nestjs/swagger",
"options": {
"introspectComments": true
}
}
]
}

The construction above enables the Introspect Comments feature (which is disabled by default). We'll dive into comments introspection below.

Hint You can read more about available options here: Swagger or GraphQL.

Note Special thanks to @qbcbyb and his amazing contribution (#585) that introduced the Introspect Comments feature!

Swagger Plugin Overview

So how can the Swagger Plugin help improve our projects?

The @nestjs/swagger plugin will automatically:

  • Annotate all DTO properties with @ApiProperty unless @ApiHideProperty is used
  • Set the required property depending on the question mark (e.g. name?: string will set required: false)
  • Set the type or enum property depending on the type (supports arrays as well)
  • Set the default property based on the assigned default value
  • Set several validation rules based on class-validator decorators (if classValidatorShim set to true)
  • Add a response decorator to every endpoint with a proper status and type (response model)
  • Generate descriptions for properties and endpoints based on comments (if introspectComments set to true)
  • Generate example values for properties based on comments (if introspectComments set to true)

If you want to provide an interactive experience with the Swagger UI without the plugin enabled, you have to duplicate a lot of code to let the package knows how your models/components should be declared in the specification.

For example, without the Nest Swagger plugin, you would have to define a simple CreateUserDto class as follows:

export class CreateUserDto {
@ApiProperty()
email: string;
@ApiProperty()
password: string;
/**
* A list of user's roles
* @example ['admin']
*/
@ApiProperty({
enum: RoleEnum,
description: `A list of user's roles`,
example: ['admin'],
default: [],
isArray: true,
})
roles: RoleEnum[] = [];
/**
* Indicates whether user is enabled or not
*/
@ApiProperty({
required: false,
description: 'Indicates whether user is enabled or not',
default: true,
})
isEnabled?: boolean = true;
}

While it's not a big deal with medium-sized projects, it becomes pretty verbose & clunky once you have a large set of classes.

Now, with the Swagger plugin enabled, the above class definition can be declared simply as follows:

export class CreateUserDto {
email: string;
password: string;
/**
* A list of user's roles
* @example ['admin']
*/
roles: RoleEnum[] = [];
/**
* Indicates whether user is enabled or not
*/
isEnabled?: boolean = true;
}

NOTE: By default, your filenames must have one of the following suffixes: ['.dto.ts', '.entity.ts'] (e.g., create-user.dto.ts) in order to be analysed by the plugin.

No boilerplate code anymore! 🎉

The plugin adds appropriate decorators on the fly based on the Abstract Syntax Tree. Hence, you no longer have to struggle with @ApiProperty decorators scattered throughout the entire project.

In addition, you may have noticed the comments we added in our code above.

With the Comments Introspection feature enabled, the swagger plugin can extract these comments and automatically provide descriptions (and examples, if defined) for properties.

GraphQL Plugin Overview

The @nestjs/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)
  • Generate descriptions for properties based on comments (if introspectComments set to true)

Without the plugin enabled, you have to manually annotate all fields to let the package knows how your types should be declared in the GraphQL schema.

For example, you could define a simple User class as follows:

@ObjectType()
export class User {
@Field((type) => ID)
id: number;
@Field()
email: string;
@Field()
password: string;
/**
* A list of user's roles
*/
@Field(() => [String], {
description: `A list of user's roles`,
})
roles: string[];
/**
* Indicates whether user is enabled or not
*/
@Field({
nullable: true,
description: 'Indicates whether user is enabled or not',
})
isEnabled?: boolean;
}

Just like before we can see that this is very verbose, and forces us to write a lot of redundant boilerplate code.

Now, with the GraphQL plugin enabled, the above class definition can be declared simply as follows:

@ObjectType()
export class User {
@Field((type) => ID)
id: number;
email: string;
password: string;
/**
* A list of user's roles
*/
roles: string[];
/**
* Indicates whether user is enabled or not
*/
isEnabled?: boolean;
}

NOTE: By default, your filenames must have one of the following suffixes in order to be analyzed by the plugin: ['.input.ts', '.args.ts', '.entity.ts', '.model.ts'] (e.g., author.entity.ts).

No boilerplate code anymore! 🎉

The plugin adds appropriate decorators on the fly based on the Abstract Syntax Tree. Hence, you no longer have to struggle with @Field decorators scattered throughout the entire project.

In addition, just like we saw before, with the Comments Introspection feature enabled, the plugin will extract comments and automatically provide descriptions for properties (if present).

In Conclusion

We hope you're as excited about these new features as we are, and we look forward to hearing your feedback and how we can improve the NestJS ecoystem even more.

Remember, Nest is open source, and if you have any amazing ideas to improve the plugin, PRs are always welcome!


Official NestJS Courses 📚

Looking to level-up your NestJS and Node.js ecosystem skills?

🚀 The NestJS Fundamentals Course is now LIVE and 25% off for a limited time!

In this extensive workshop-style course, we'll incrementally build a NestJS application together.

We'll learn about all of the fundamental building blocks, interact with both SQL & NoSql databases, use modern Node.js application techniques, unit / e2e testing, tips, tricks, and overall best-practices!


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.


Support

Nest is an MIT-licensed open source project with its ongoing development made possible thanks to the support by the community, thank you!

<script>

If you want to join them, you can find more here.

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. ❤


Learn NestJS - Official NestJS Courses 📚

Level-up your NestJS and Node.js ecosystem skills in these incremental workshop-style courses, from the NestJS Creator himself, and help support the NestJS framework! 🐈

🚀 The NestJS Fundamentals Course is now LIVE and 25% off for a limited time!

🎉 NEW - NestJS Course Extensions now live!
#NestJS
#NodeJS
#JavaScript

Share this Post!

📬 Trilon Newsletter

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

More from the Trilon Blog .

Jay McDoniel | Trilon Consulting
Jay McDoniel

NestJS Metadata Deep Dive

In this article we'll be doing a deep-dive and learning about how NestJS uses Metadata internally for everything from dependency injection, to decorators we use everyday!

Read More
Kamil Mysliwiec | Trilon Consulting
Kamil Mysliwiec

NestJS v10 is now available

Today I am excited to announce the official release of Nest 10: A progressive Node.js framework for building efficient and enterprise-grade, server-side applications.

Read More
Manuel Carballido | Trilon Consulting
Manuel Carballido

Implementing data source agnostic services with NestJS

Learn how to implement data source logic in an agnostic way in yours NestJS applications.

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-2023 Trilon.