-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #384 from johnbiundo/decorators
docs(custom-decorators.md): edits for clarity and grammar
- Loading branch information
Showing
1 changed file
with
35 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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: | ||
|
||
<blockquote class="external"> | ||
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 (or Fastify) objects they represent | ||
|
||
<table> | ||
<tbody> | ||
|
@@ -49,15 +49,15 @@ Nest provides a set of useful **param decorators** that you can use together wit | |
</tbody> | ||
</table> | ||
|
||
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,56 @@ 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: | ||
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 <a href="techniques/authentication#user-object">authentication layer</a> validates requests and attaches a user entity to the request object. The user entity for an authenticated request might look like: | ||
|
||
```typescript | ||
@@filename() | ||
@Get() | ||
async findOne(@User('test') user: UserEntity) { | ||
console.log(user); | ||
} | ||
@@switch | ||
@Get() | ||
@Bind(User('test')) | ||
async findOne(user) { | ||
console.log(user); | ||
```json | ||
{ | ||
"id": 101, | ||
"firstName": "Alan", | ||
"lastName": "Turing", | ||
"email": "[email protected]", | ||
"roles": ["admin"] | ||
} | ||
``` | ||
|
||
Will make possible to access the `test` string via the `data` argument: | ||
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) => { | ||
console.log(data); // test | ||
return req.user; | ||
return data ? req.user && req.user[data] : req.user; | ||
}); | ||
@@switch | ||
import { createParamDecorator } from '@nestjs/common'; | ||
|
||
export const User = createParamDecorator((data, req) => { | ||
console.log(data); // test | ||
return req.user; | ||
return data ? req.user && req.user[data] : req.user; | ||
}); | ||
``` | ||
|
||
Here's how you could then access a particular property via the `@User()` decorator in the controller: | ||
|
||
```typescript | ||
@@filename() | ||
@Get() | ||
async findOne(@User('firstName') firstName: string) { | ||
console.log(`Hello ${firstName}`); | ||
} | ||
@@switch | ||
@Get() | ||
@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()`). 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() | ||
|