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 setrequired: false
) - Set the
type
orenum
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 totrue
) - 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 totrue
) - Generate example values for properties based on comments (if
introspectComments
set totrue
)
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 setnullable: true
) - Set the
type
property depending on the type (supports arrays as well) - Generate descriptions for properties based on comments (if
introspectComments
set totrue
)
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>We strongly believe that someday we could fully focus on #opensource to make @nodejs world better 🚀🔥 @opencollect
— NestJS (@nestframework) April 25, 2018
- enjoy using @nestframework?
- ask your company to support us:
- https://t.co/taYS49lllr pic.twitter.com/L1O9Vf5uhS
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 Advanced Concepts Course now LIVE!
- NestJS Authentication / Authorization Course now LIVE!
- NestJS GraphQL Course (code-first & schema-first approaches) are now LIVE!
- NestJS Authentication / Authorization Course now LIVE!