@ivorpad/nestjs-cookies-fastify
v1.0.0
Published
Decorators for Managing Cookies with NestJS and Fastify
Downloads
2
Readme
Installation
npm install @ivorpad/nestjs-cookies-fastify
Motivation
NestJS doesn't currently have decorators for getting and setting cookies. While it's not too hard to read cookies, it's convenient to have a parameter decorator to do so.
@Post('login')
login(@Cookies() cookies) {
console.log('Got cookies:', cookies);
}
Setting cookies is a little less straightforward. You either need to utilize the platform-specific
response (res
) object, or write an interceptor. The former is pretty straightforward, though
takes a non-Nest-like imperative style. It also puts you into
manual response mode,
meaning you can no longer rely on features like @Render()
, @HttpCode()
or interceptors that modify the response,
and makes testing harder (you'll have to mock the response
object, etc.). The @SetCookies()
decorator from this package wraps an interceptor
in a declarative decorator that solves these issues.
Collectively, the @Cookies()
, @SignedCookies()
, @SetCookies()
and @ClearCookies()
decorators in this package
provide a convenient set of features that make it easier to manage cookies in a standard and declarative way,
and minimize boilerplate code.
See Also
If you like these decorators, you may also be interested in the NestJS Redirect decorator.
Importing the Decorators
Import the decorators, just as you would other Nest decorators, in the controllers that use them as shown below:
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
import { Cookies, SignedCookies } from '@nestjsplus/cookies';
@Controller()
export class AppController {
...
Reading Cookies
Reading cookies requires the fastify-cookie package to be installed.
Cookies
Use the @Cookies()
route parameter decorator to get "regular" cookies.
@Get('get')
get(@Cookies() cookies): string {
console.log('cookies: ', cookies);
return this.appService.getHello();
}
This will bind an array of all (non-signed) cookies to the cookies
parameter.
See below to access a named cookie.
Setting Cookies
Use the @SetCookies()
route handler method decorator to set cookies.
Here's the API:
@SetCookies(
options?: CookieOptions,
cookies?: CookieSettings | CookieSettings[]
)
Here's how it works. You have two options, depending on whether the cookie settings are static or dynamic.
For static cookies, where the cookie name and/or value are known at compile time, you can set them in the
@SetCookies()
decorator by passing a CookieSettings object.For example:
@SetCookies({name: 'cookie1', value: 'cookie 1 value'})
@Get('set')
set() {
...
}
For dynamic cookies, where the cookie name and/or value are computed at run-time, you can provide the cookie name/value pairs to be set when the route handler method runs. Provide these values by passing them on the
req._cookies
array property. (The decorator creates the_cookies
property automatically for you). Note: Of course if you are using this technique, you are de facto accessing therequest
object, so you must bind@Request()
to a route parameter.For example:
set(@Request() req) {
const cookie1Value = 'chocoloate chip';
req._cookies = [
{
name: 'cookie1',
value: cookie1Value,
options: {
signed: true,
sameSite: true,
},
},
{ name: 'cookie2', value: 'oatmeal raisin' },
];
...
Defaults and overriding
You can mix and match CookieOptions
and CookieSettings
in the decorator and
in the method body as needed. This example
shows dynamic cookies with defaults inherited from the decorator, and
overrides in the body:
@SetCookies({httpOnly: true},
[
{name: 'cookie1', value: 'cookie 1 value'},
{name: 'cookie2', value: 'cookie 2 value', {httpOnly: false}}
]
)
As a result of the above, cookie1
will be set as HttpOnly
, but cookie2
will not.
- Set default cookie options by passing a
CookieOptions
object in the decorator. Options set on individual cookies, if provided, override these defaults.
Cookie Settings
As shown above, each cookie you set has the shape:
interface CookieSettings {
/**
* name of the cookie.
*/
name: string;
/**
* value of the cookie.
*/
value?: string;
/**
* cookie options.
*/
options?: CookieOptions;
}
If options
are provided for a cookie, they completely replace any options
specified in the @SetCookies()
decorator. If omitted for a cookie, they default
to options specified on the @SetCookies()
decorator.
CookieOptions
Cookie options may be set at the method level (@SetCookies()
), providing a set of
defaults, or for individual cookies. In either case, they have the following shape:
interface CookieOptions {
/**
* Domain name for the cookie.
*/
domain?: string;
/**
* A synchronous function used for cookie value encoding. Defaults to encodeURIComponent.
*/
encode?: (val: string) => string;
/**
* Expiry date of the cookie in GMT. If not specified or set to 0, creates a session cookie.
*/
expires?: Date;
/**
* Flags the cookie to be accessible only by the web server.
*/
httpOnly?: boolean;
/**
* Convenient option for setting the expiry time relative to the current time in milliseconds.
*/
maxAge?: number;
/**
* Path for the cookie. Defaults to “/”.
*/
path?: string;
/**
* Marks the cookie to be used with HTTPS only.
*/
secure?: boolean;
/**
* Indicates if the cookie should be signed.
*/
signed?: boolean;
/**
* Value of the “SameSite” Set-Cookie attribute. More information at
* https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00#section-4.1.1.
*/
sameSite?: boolean | string;
}
Route Handler Results and Behavior
The route handler otherwise proceeds as normal. It can return values, and it can
use other route handler method decorators (such as @Render()
) and other route
parameter decorators (such as @Headers()
, @Query()
).
Example
Setting cookies isn't hard! See a full example here in the test folder.
Clearing (deleting) Cookies
Delete cookies in one of two ways:
- Use
@SetCookies()
and pass in only the cookie name (leave the value property off of the object). - Use
@ClearCookies()
, passing in a comma separated list of cookies to clear.
@ClearCookies('cookie1', 'cookie2')
@Get('kill')
@Render('clear')
kill() {
return { message: 'cookies killed!' };
}
Author
- John Biundo (Y Prospect on Discord)
License
Licensed under the MIT License - see the LICENSE file for details.