Skip to content

Commit

Permalink
Merge pull request #384 from johnbiundo/decorators
Browse files Browse the repository at this point in the history
docs(custom-decorators.md): edits for clarity and grammar
  • Loading branch information
kamilmysliwiec authored May 9, 2019
2 parents b8ab5e3 + 10df964 commit e399998
Showing 1 changed file with 35 additions and 23 deletions.
58 changes: 35 additions & 23 deletions content/custom-decorators.md
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.
Expand All @@ -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>
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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()
Expand Down

0 comments on commit e399998

Please sign in to comment.