From d352c8b18a0f2ecb83624e4cbfad715baeb3b880 Mon Sep 17 00:00:00 2001 From: John Biundo Date: Thu, 25 Apr 2019 13:14:45 -0700 Subject: [PATCH 1/3] docs(custom-decorators.md) Edits --- content/custom-decorators.md | 50 ++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/content/custom-decorators.md b/content/custom-decorators.md index 4b261cddd8..24a988e99d 100644 --- a/content/custom-decorators.md +++ b/content/custom-decorators.md @@ -1,6 +1,6 @@ ### Custom route decorators -Nest is built around a language feature called **decorators**. It's a well-known concept in a lot of commonly used programming languages, but in the JavaScript world, it's still relatively new. In order to better understand how the decorators work, you should take a look at [this](https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841) article. Here's a simple definition: +Nest is built around a language feature called **decorators**. Decorators are a well-known concept in a lot of commonly used programming languages, but in the JavaScript world, they're still relatively new. In order to better understand how decorators work, we recommend reading [this article](https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841). Here's a simple definition:
An ES2016 decorator is an expression which returns a function and can take a target, name and property descriptor as arguments. @@ -10,7 +10,7 @@ Nest is built around a language feature called **decorators**. It's a well-known #### Param decorators -Nest provides a set of useful **param decorators** that you can use together with the HTTP route handlers. Below is a comparison of the decorators with the plain express objects. +Nest provides a set of useful **param decorators** that you can use together with the HTTP route handlers. Below is a list of the provided decorators and the plain Express objects they represent @@ -49,15 +49,15 @@ Nest provides a set of useful **param decorators** that you can use together wit
-Additionally, you can create your own, **custom decorator**. Why it is useful? +Additionally, you can create your own **custom decorators**. Why is this useful? -In the node.js world, it's a common practice to attach properties to the **request** object. Then you have to manually grab them every time in the route handlers, for example, using following construction: +In the node.js world, it's common practice to attach properties to the **request** object. Then you manually extract them in each route handler, using code like the following: ```typescript const user = req.user; ``` -In order to make it more readable and transparent, we can create a `@User()` decorator and reuse it across all existing controllers. +In order to make your code more readable and transparent, you can create a `@User()` decorator and reuse it across all of your controllers. ```typescript @@filename(user.decorator) @@ -86,44 +86,44 @@ async findOne(user) { #### Passing data -When the behavior of your decorator depends on some conditions, you may use the `data` param to pass an argument to the decorator's factory function. For example, the construction below: - -```typescript -@@filename() -@Get() -async findOne(@User('test') user: UserEntity) { - console.log(user); -} -@@switch -@Get() -@Bind(User('test')) -async findOne(user) { - console.log(user); -} -``` - -Will make possible to access the `test` string via the `data` argument: +When the behavior of your decorator depends on some conditions, you can use the `data` parameter to pass an argument to the decorator's factory function: ```typescript @@filename(user.decorator) import { createParamDecorator } from '@nestjs/common'; export const User = createParamDecorator((data: string, req) => { - console.log(data); // test + req.user.userType = data; return req.user; }); @@switch import { createParamDecorator } from '@nestjs/common'; export const User = createParamDecorator((data, req) => { - console.log(data); // test + req.user.userType = data; return req.user; }); ``` +Here's how you could then access this value via the `custom param decorator` in the controller: + +```typescript +@@filename() +@Get() +async findOne(@User('test') user: UserEntity) { + console.log(`User type is ${user.userType}`); +} +@@switch +@Get() +@Bind(User('test')) +async findOne(user) { + console.log(`User type is ${user.userType}`); +} +``` + #### Working with pipes -Nest treats custom param decorators in the same fashion as the built-in ones (`@Body()`, `@Param()` and `@Query()`). It means that pipes are executed for the custom annotated parameters as well (in this case, for the `user` argument). Moreover, you can apply the pipe directly to the custom decorator: +Nest treats custom param decorators in the same fashion as the built-in ones (`@Body()`, `@Param()` and `@Query()`). This means that pipes are executed for the custom annotated parameters as well (in our examples, the `user` argument). Moreover, you can apply the pipe directly to the custom decorator: ```typescript @@filename() From 6ca426992225d6d8e18406ddfef1cf81fcd053d0 Mon Sep 17 00:00:00 2001 From: Kamil Mysliwiec Date: Fri, 26 Apr 2019 09:00:25 +0200 Subject: [PATCH 2/3] Update custom-decorators.md --- content/custom-decorators.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/custom-decorators.md b/content/custom-decorators.md index 24a988e99d..5f60442822 100644 --- a/content/custom-decorators.md +++ b/content/custom-decorators.md @@ -10,7 +10,7 @@ Nest is built around a language feature called **decorators**. Decorators are a #### Param decorators -Nest provides a set of useful **param decorators** that you can use together with the HTTP route handlers. Below is a list of the provided decorators and the plain Express objects they represent +Nest provides a set of useful **param decorators** that you can use together with the HTTP route handlers. Below is a list of the provided decorators and the plain Express (or Fastify) objects they represent From 727bdc0698e115ecf265143dc519254c898081d6 Mon Sep 17 00:00:00 2001 From: John Biundo Date: Sat, 27 Apr 2019 09:34:27 -0700 Subject: [PATCH 3/3] docs(custom-decorators.md): improve 'Passing data' --- content/custom-decorators.md | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/content/custom-decorators.md b/content/custom-decorators.md index 24a988e99d..e48597d316 100644 --- a/content/custom-decorators.md +++ b/content/custom-decorators.md @@ -86,41 +86,53 @@ async findOne(user) { #### Passing data -When the behavior of your decorator depends on some conditions, you can use the `data` parameter to pass an argument to the decorator's factory function: +When the behavior of your decorator depends on some conditions, you can use the `data` parameter to pass an argument to the decorator's factory function. One use case for this is a custom decorator that extracts properties from the request object by key. Let's assume, for example, that our authentication layer validates requests and attaches a user entity to the request object. The user entity for an authenticated request might look like: + +```json +{ + "id": 101, + "firstName": "Alan", + "lastName": "Turing", + "email": "alan@email.com", + "roles": ["admin"] +} +``` + +Let's define a decorator that takes a property name as key, and returns the associated value if it exists (or undefined if it doesn't exist, or if the `user` object has not been created). ```typescript @@filename(user.decorator) import { createParamDecorator } from '@nestjs/common'; export const User = createParamDecorator((data: string, req) => { - req.user.userType = data; - return req.user; + return data ? req.user && req.user[data] : req.user; }); @@switch import { createParamDecorator } from '@nestjs/common'; export const User = createParamDecorator((data, req) => { - req.user.userType = data; - return req.user; + return data ? req.user && req.user[data] : req.user; }); ``` -Here's how you could then access this value via the `custom param decorator` in the controller: +Here's how you could then access a particular property via the `@User()` decorator in the controller: ```typescript @@filename() @Get() -async findOne(@User('test') user: UserEntity) { - console.log(`User type is ${user.userType}`); +async findOne(@User('firstName') firstName: string) { + console.log(`Hello ${firstName}`); } @@switch @Get() -@Bind(User('test')) -async findOne(user) { - console.log(`User type is ${user.userType}`); +@Bind(User('firstName')) +async findOne(firstName) { + console.log(`Hello ${firstName}`); } ``` +You can use this same decorator with different keys to access different properties. If the `user` object is deep or complex, this can make for easier and more readable request handler implementations. + #### Working with pipes Nest treats custom param decorators in the same fashion as the built-in ones (`@Body()`, `@Param()` and `@Query()`). This means that pipes are executed for the custom annotated parameters as well (in our examples, the `user` argument). Moreover, you can apply the pipe directly to the custom decorator: