Skip to content

Commit 26002a2

Browse files
docs(): add docs about cookies
1 parent 471e34b commit 26002a2

File tree

6 files changed

+148
-4
lines changed

6 files changed

+148
-4
lines changed

content/controllers.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ We attached the metadata to the module class using the `@Module()` decorator, an
506506

507507
<app-banner-shop></app-banner-shop>
508508

509-
#### Appendix: Library-specific approach
509+
#### Library-specific approach
510510

511511
So far we've discussed the Nest standard way of manipulating responses. The second way of manipulating the response is to use a library-specific [response object](https://expressjs.com/en/api.html#res). In order to inject a particular response object, we need to use the `@Res()` decorator. To show the differences, let's rewrite the `CatsController` to the following:
512512

content/custom-decorators.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export const User = createParamDecorator(
120120
const request = ctx.switchToHttp().getRequest();
121121
const user = request.user;
122122

123-
return data ? user && user[data] : user;
123+
return data ? user?.[data] : user;
124124
},
125125
);
126126
@@switch

content/techniques/cookies.md

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
### Cookies
2+
3+
An **HTTP cookie** is a small piece of data stored by the user's browser. Cookies were designed to be a reliable mechanism for websites to remember stateful information. When the user visits the website again, the cookie is automatically sent with the request.
4+
5+
#### Use with Express (default)
6+
7+
First install the required package (and its types for TypeScript users):
8+
9+
```shell
10+
$ npm i cookie-parser
11+
$ npm i -D @types/cookie-parser
12+
```
13+
14+
Once the installation is complete, apply the `cookie-parser` middleware as global middleware (for example, in your `main.ts` file).
15+
16+
```typescript
17+
import * as cookieParser from 'cookie-parser';
18+
// somewhere in your initialization file
19+
app.use(cookieParser());
20+
```
21+
22+
You can also pass several options to the `cookieParser` middleware:
23+
24+
- `secret` a string or array used for signing cookies. This is optional and if not specified, will not parse signed cookies. If a string is provided, this is used as the secret. If an array is provided, an attempt will be made to unsign the cookie with each secret in order.
25+
- `options` an object that is passed to `cookie.parse` as the second option. See [cookie](https://www.npmjs.org/package/cookie) for more information.
26+
27+
The middleware will parse the `Cookie` header on the request and expose the cookie data as the property `req.cookies` and, if a secret was provided, as the property `req.signedCookies`. These properties are name value pairs of the cookie name to cookie value.
28+
29+
When secret is provided, this module will unsign and validate any signed cookie values and move those name value pairs from req.cookies into `req.signedCookies`. A signed cookie is a cookie that has a value prefixed with `s:`. Signed cookies that fail signature validation will have the value `false` instead of the tampered value.
30+
31+
With this in place, you can now read cookies from within the route handlers, as follows:
32+
33+
```typescript
34+
@Get()
35+
findAll(@Req() request: Request) {
36+
console.log(request.cookies); // or "request.cookies['cookieKey']"
37+
// or console.log(request.signedCookies);
38+
}
39+
```
40+
41+
> info **Hint** The `@Req()` decorator is imported from the `@nestjs/common`, while `Request` from the `express` package.
42+
43+
To attach a cookie to an outgoing response, use the `Response#cookie()` method:
44+
45+
```typescript
46+
@Get()
47+
findAll(@Res({ passthrough: true }) response: Response) {
48+
response.cookie('key', 'value')
49+
}
50+
```
51+
52+
> warning **Warning** If you want to leave the response handling logic to the framework, remember to set the `passthrough` option to `true`, as shown above. Read more [here](/controllers#appendix-library-specific-approach).
53+
54+
> info **Hint** The `@Res()` decorator is imported from the `@nestjs/common`, while `Response` from the `express` package.
55+
56+
#### Use with Fastify
57+
58+
First install the required package:
59+
60+
```shell
61+
$ npm i fastify-cookie
62+
```
63+
64+
Once the installation is complete, register the `fastify-cookie` plugin:
65+
66+
```typescript
67+
import fastifyCookie from 'fastify-cookie';
68+
69+
// somewhere in your initialization file
70+
const app = await NestFactory.create<NestFastifyApplication>(
71+
AppModule,
72+
new FastifyAdapter(),
73+
);
74+
app.register(fastifyCookie, {
75+
secret: 'my-secret', // for cookies signature
76+
});
77+
```
78+
79+
With this in place, you can now read cookies from within the route handlers, as follows:
80+
81+
```typescript
82+
@Get()
83+
findAll(@Req() request: FastifyRequest) {
84+
console.log(request.cookies); // or "request.cookies['cookieKey']"
85+
}
86+
```
87+
88+
> info **Hint** The `@Req()` decorator is imported from the `@nestjs/common`, while `FastifyRequest` from the `fastify` package.
89+
90+
To attach a cookie to an outgoing response, use the `FastifyReply#setCookie()` method:
91+
92+
```typescript
93+
@Get()
94+
findAll(@Res({ passthrough: true }) response: FastifyReply) {
95+
response.setCookie('key', 'value')
96+
}
97+
```
98+
99+
To read more about `FastifyReply#setCookie()` method, check out this [page](https://github.com/fastify/fastify-cookie#sending).
100+
101+
> warning **Warning** If you want to leave the response handling logic to the framework, remember to set the `passthrough` option to `true`, as shown above. Read more [here](/controllers#appendix-library-specific-approach).
102+
103+
> info **Hint** The `@Res()` decorator is imported from the `@nestjs/common`, while `FastifyReply` from the `fastify` package.
104+
105+
#### Creating a custom decorator (cross-platform)
106+
107+
To provide a convenient, declarative way of accessing incoming cookies, we can create a [custom decorator](/custom-decorators).
108+
109+
```typescript
110+
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
111+
112+
export const Cookies = createParamDecorator(
113+
(data: string, ctx: ExecutionContext) => {
114+
const request = ctx.switchToHttp().getRequest();
115+
return data ? request.cookies?.[data] : request.cookies;
116+
},
117+
);
118+
```
119+
120+
The `@Cookies()` decorator will extract all cookies, or a named cookie from the `req.cookies` object and populate the decorated parameter with that value.
121+
122+
With this in place, we can now use the decorator in a route handler signature, as follows:
123+
124+
```typescript
125+
@Get()
126+
findAll(@Cookies('name') name: string) {}
127+
```

src/app/homepage/menu/menu.component.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,11 @@ export class MenuComponent implements OnInit {
9090
{ title: 'Caching', path: '/techniques/caching' },
9191
{ title: 'Serialization', path: '/techniques/serialization' },
9292
{ title: 'Task scheduling', path: '/techniques/task-scheduling' },
93-
{ title: 'Compression', path: '/techniques/compression' },
9493
{ title: 'Security', path: '/techniques/security' },
9594
{ title: 'Queues', path: '/techniques/queues' },
9695
{ title: 'Logger', path: '/techniques/logger' },
96+
{ title: 'Cookies', path: '/techniques/cookies' },
97+
{ title: 'Compression', path: '/techniques/compression' },
9798
{ title: 'File upload', path: '/techniques/file-upload' },
9899
{ title: 'HTTP module', path: '/techniques/http-module' },
99100
{ title: 'Model-View-Controller', path: '/techniques/mvc' },
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { ChangeDetectionStrategy, Component } from '@angular/core';
2+
import { BasePageComponent } from '../../page/page.component';
3+
4+
@Component({
5+
selector: 'app-cookies',
6+
templateUrl: './cookies.component.html',
7+
changeDetection: ChangeDetectionStrategy.OnPush,
8+
})
9+
export class CookiesComponent extends BasePageComponent {}

src/app/homepage/pages/techniques/techniques.module.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { AuthenticationComponent } from './authentication/authentication.compone
66
import { CachingComponent } from './caching/caching.component';
77
import { CompressionComponent } from './compression/compression.component';
88
import { ConfigurationComponent } from './configuration/configuration.component';
9+
import { CookiesComponent } from './cookies/cookies.component';
910
import { FileUploadComponent } from './file-upload/file-upload.component';
1011
import { HttpModuleComponent } from './http-module/http-module.component';
1112
import { LoggerComponent } from './logger/logger.component';
@@ -90,6 +91,11 @@ const routes: Routes = [
9091
component: SecurityComponent,
9192
data: { title: 'Security' },
9293
},
94+
{
95+
path: 'cookies',
96+
component: CookiesComponent,
97+
data: { title: 'Cookies' },
98+
},
9399
{
94100
path: 'task-scheduling',
95101
component: TaskSchedulingComponent,
@@ -135,7 +141,8 @@ const routes: Routes = [
135141
ValidationComponent,
136142
CachingComponent,
137143
SerializationComponent,
138-
ServerSentEventsComponent
144+
ServerSentEventsComponent,
145+
CookiesComponent,
139146
],
140147
})
141148
export class TechniquesModule {}

0 commit comments

Comments
 (0)