Skip to content

Commit 410dd24

Browse files
Merge branch 'master' into patch-1
2 parents 33df80f + e00b4b3 commit 410dd24

32 files changed

+2284
-1198
lines changed

.github/workflows/lighthouse.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
name: Lighthouse
2+
3+
on:
4+
pull_request:
5+
paths-ignore:
6+
- 'content/**/*.md'
7+
8+
jobs:
9+
build:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- uses: actions/checkout@v1
14+
- name: Use Node.js 12.x
15+
uses: actions/setup-node@v1
16+
with:
17+
node-version: 12.x
18+
# Build needs around 400 seconds on Netlify.
19+
# We can not rely on "Waiting for 200", since the user
20+
# might push another commit to an existing PR, meaning
21+
# the deploy preview is already online.
22+
- name: Sleep 400 seconds
23+
run: sleep 400
24+
- name: Waiting for 200 from the Netlify Preview
25+
uses: jakepartusch/wait-for-netlify-action@v1
26+
id: wait-for-netflify-preview
27+
with:
28+
site_name: 'docs-nestjs'
29+
max_timeout: 600
30+
- name: Run Lighthouse on urls and validate with lighthouserc
31+
uses: treosh/lighthouse-ci-action@v2
32+
with:
33+
urls: |
34+
${{ steps.wait-for-netflify-preview.outputs.url }}
35+
${{ steps.wait-for-netflify-preview.outputs.url }}/first-steps
36+
runs: 5
37+
configPath: './lighthouserc.json'
38+
uploadArtifacts: true
39+
temporaryPublicStorage: true

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
12.17.0
1+
12.18.1

content/cli/scripts.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ A Nest application is a **standard** TypeScript application that needs to be com
1010

1111
This goal is accomplished through a combination of the `nest` command, a locally installed TypeScript compiler, and `package.json` scripts. We describe how these technologies work together below. This should help you understand what's happening at each step of the build/execute process, and how to customize that behavior if necessary.
1212

13-
### The nest binary
13+
#### The nest binary
1414

1515
The `nest` command is an OS level binary (i.e., runs from the OS command line). This command actually encompasses 3 distinct areas, described below. We recommend that you run the build (`nest build`) and execution (`nest start`) sub-commands via the `package.json` scripts provided automatically when a project is scaffolded (see [typescript starter](https://github.com/nestjs/typescript-starter) if you wish to start by cloning a repo, instead of running `nest new`).
1616

@@ -30,7 +30,7 @@ See the [nest start](https://docs.nestjs.com/cli/usages#nest-start) documentatio
3030

3131
The `nest generate` commands, as the name implies, generate new Nest projects, or components within them.
3232

33-
### Package scripts
33+
#### Package scripts
3434

3535
Running the `nest` commands at the OS command level requires that the `nest` binary be installed globally. This is a standard feature of npm, and outside of Nest's direct control. One consequence of this is that the globally installed `nest` binary is **not** managed as a project dependency in `package.json`. For example, two different developers can be running two different versions of the `nest` binary. The standard solution for this is to use package scripts so that you can treat the tools used in the build and execute steps as development dependencies.
3636

@@ -54,11 +54,11 @@ These commands use npm's script running capabilities to execute `nest build` or
5454

5555
For most developers/teams, it is recommended to utilize the package scripts for building and executing their Nest projects. You can fully customize the behavior of these scripts via their options (`--path`, `--webpack`, `--webpackPath`) and/or customize the `tsc` or webpack compiler options files (e.g., `tsconfig.json`) as needed. You are also free to run a completely custom build process to compile the TypeScript (or even to execute TypeScript directly with `ts-node`).
5656

57-
### Backward compatibility
57+
#### Backward compatibility
5858

5959
Because Nest applications are pure TypeScript applications, previous versions of the Nest build/execute scripts will continue to operate. You are not required to upgrade them. You can choose to take advantage of the new `nest build` and `nest start` commands when you are ready, or continue running previous or customized scripts.
6060

61-
### Migration
61+
#### Migration
6262

6363
While you are not required to make any changes, you may want to migrate to using the new CLI commands instead of using tools such as `tsc-watch` or `ts-node`. In this case, simply install the latest version of the `@nestjs/cli`, both globally and locally:
6464

content/controllers.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -442,37 +442,38 @@ export class CatsController {
442442
}
443443
}
444444
@@switch
445-
import { Controller, Get, Query, Post, Body, Put, Param, Delete } from '@nestjs/common';
445+
import { Controller, Get, Query, Post, Body, Put, Param, Delete, Bind } from '@nestjs/common';
446446
447447
@Controller('cats')
448448
export class CatsController {
449449
@Post()
450450
@Bind(Body())
451-
create(@Body() createCatDto) {
451+
create(createCatDto) {
452452
return 'This action adds a new cat';
453453
}
454454
455455
@Get()
456456
@Bind(Query())
457-
findAll(@Query() query) {
457+
findAll(query) {
458+
console.log(query);
458459
return `This action returns all cats (limit: ${query.limit} items)`;
459460
}
460461
461462
@Get(':id')
462463
@Bind(Param('id'))
463-
findOne(@Param('id') id) {
464+
findOne(id) {
464465
return `This action returns a #${id} cat`;
465466
}
466467
467468
@Put(':id')
468469
@Bind(Param('id'), Body())
469-
update(@Param('id') id, @Body() updateCatDto) {
470+
update(id, updateCatDto) {
470471
return `This action updates a #${id} cat`;
471472
}
472473
473474
@Delete(':id')
474475
@Bind(Param('id'))
475-
remove(@Param('id') id) {
476+
remove(id) {
476477
return `This action removes a #${id} cat`;
477478
}
478479
}

content/custom-decorators.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Nest is built around a language feature called **decorators**. Decorators are a
55
<blockquote class="external">
66
An ES2016 decorator is an expression which returns a function and can take a target, name and property descriptor as arguments.
77
You apply it by prefixing the decorator with an <code>@</code> character and placing this at the very top of what
8-
you are trying to decorate. Decorators can be defined for either a class or a property.
8+
you are trying to decorate. Decorators can be defined for either a class, a method or a property.
99
</blockquote>
1010

1111
#### Param decorators

content/discover/who-uses.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@
152152
"url": "https://bedu.org",
153153
"width": "100px"
154154
},
155+
{
156+
"logo": "/assets/logo/shopback.png",
157+
"url": "https://shopback.com"
158+
},
155159
{
156160
"logo": "/assets/logo/facile.png",
157161
"url": "https://www.facile.it",
@@ -201,6 +205,7 @@
201205
"https://www.mediktiv.com",
202206
"https://harmonize.health",
203207
"https://accerlery.be",
204-
"https://www.facile.it"
208+
"https://www.facile.it",
209+
"https://shopback.com"
205210
]
206211
}

content/fundamentals/lifecycle-events.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ The following diagram depicts the sequence of key application lifecycle events,
88

99
<figure><img src="/assets/lifecycle-events.png" /></figure>
1010

11-
<p style="clear: both;"></p>
12-
1311
#### Lifecycle events
1412

1513
Lifecycle events happen during application bootstrapping and shutdown. Nest calls registered lifecycle hook methods on `modules`, `injectables` and `controllers` at each of the following lifecycle events (**shutdown hooks** need to be enabled first, as described [below](https://docs.nestjs.com/fundamentals/lifecycle-events#application-shutdown)). As shown in the diagram above, Nest also calls the appropriate underlying methods to begin listening for connections, and to stop listening for connections.
@@ -24,7 +22,9 @@ In the following table, `onModuleDestroy`, `beforeApplicationShutdown` and `onAp
2422
| `beforeApplicationShutdown()`\* | Called after all `onModuleDestroy()` handlers have completed (Promises resolved or rejected);<br />once complete (Promises resolved or rejected), all existing connections will be closed (`app.close()` called). |
2523
| `onApplicationShutdown()`\* | Called after connections close (`app.close()` resolves. |
2624

27-
\* For these events, if you're not calling `app.close()` explicitly, you must opt-in to make them work with system signals such as `SIGTERM`. See [Application shutdown](#application-shutdown) below.
25+
\* For these events, if you're not calling `app.close()` explicitly, you must opt-in to make them work with system signals such as `SIGTERM`. See [Application shutdown](#application-shutdown) below.
26+
27+
> warning **Warning** The lifecycle hooks listed above are not triggered for **request-scoped** classes. Request-scoped classes are not tied to the application lifecycle and their lifespan is unpredictable. They are exclusively created for each request and automatically garbage-collected after the response is sent.
2828
2929
#### Usage
3030

content/graphql/complexity.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
### Complexity
2+
3+
> warning **Warning** This chapter applies only to the code first approach.
4+
5+
Query complexity allows you to define how complex certain fields are, and to restrict queries with a **maximum complexity**. The idea is to define how complex each field is by using a simple number. A common default is to give each field a complexity of `1`. In addition, the complexity calculation of a GraphQL query can be customized with so-called complexity estimators. A complexity estimator is a simple function that calculates the complexity for a field. You can add any number of complexity estimators to the rule, which are then executed one after another. The first estimator that returns a numeric complexity value determines the complexity for that field.
6+
7+
The `@nestjs/graphql` package integrates very well with tools like [graphql-query-complexity](https://github.com/slicknode/graphql-query-complexity) that provides a cost analysis-based solution. With this library, you can reject queries to your GraphQL server that are deemed too costly to execute.
8+
9+
#### Installation
10+
11+
To begin using it, we first install the required dependency.
12+
13+
```bash
14+
$ npm install --save graphql-query-complexity
15+
```
16+
17+
#### Getting started
18+
19+
Once the installation process is complete, we can define the `ComplexityPlugin` class:
20+
21+
```typescript
22+
import { GraphQLSchemaHost, Plugin } from '@nestjs/graphql';
23+
import {
24+
ApolloServerPlugin,
25+
GraphQLRequestListener,
26+
} from 'apollo-server-plugin-base';
27+
import { GraphQLError } from 'graphql';
28+
import {
29+
fieldExtensionsEstimator,
30+
getComplexity,
31+
simpleEstimator,
32+
} from 'graphql-query-complexity';
33+
34+
@Plugin()
35+
export class ComplexityPlugin implements ApolloServerPlugin {
36+
constructor(private gqlSchemaHost: GraphQLSchemaHost) {}
37+
38+
requestDidStart(): GraphQLRequestListener {
39+
const { schema } = this.gqlSchemaHost;
40+
41+
return {
42+
didResolveOperation({ request, document }) {
43+
const complexity = getComplexity({
44+
schema,
45+
operationName: request.operationName,
46+
query: document,
47+
variables: request.variables,
48+
estimators: [
49+
fieldExtensionsEstimator(),
50+
simpleEstimator({ defaultComplexity: 1 }),
51+
],
52+
});
53+
if (complexity >= 20) {
54+
throw new GraphQLError(
55+
`Query is too complex: ${complexity}. Maximum allowed complexity: 20`,
56+
);
57+
}
58+
console.log('Query Complexity:', complexity);
59+
},
60+
};
61+
}
62+
}
63+
```
64+
65+
For demonstration purposes, we specified the maximum allowed complexity as `20`. In the example above, we used 2 estimators, the `simpleEstimator` and the `fieldExtensionsEstimator`.
66+
67+
- `simpleEstimator`: the simple estimator returns a fixed complexity for each field
68+
- `fieldExtensionsEstimator`: the field extensions estimator extracts the complexity value for each field of your schema
69+
70+
> info **Hint** Remember to add this class to the providers array in any module.
71+
72+
#### Field-level complexity
73+
74+
With this plugin in place, we can now define the complexity for any field by specifying the `complexity` property in the options object passed into the `@Field()` decorator, as follows:
75+
76+
```typescript
77+
@Field({ complexity: 3 })
78+
title: string;
79+
```
80+
81+
Alternatively, you can define the estimator function:
82+
83+
```typescript
84+
@Field({ complexity: (options: ComplexityEstimatorArgs) => ... })
85+
title: string;
86+
```

content/graphql/extensions.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
### Extensions
2+
3+
> warning **Warning** This chapter applies only to the code first approach.
4+
5+
Extensions is an **advanced, low-level feature** that lets you define arbitrary data in the types configuration. Attaching custom metadata to certain fields allows you to create more sophisticated, generic solutions. For example, with extensions, you can define field-level roles required to access particular fields. Such roles can be reflected at runtime to determine whether the caller has sufficient permissions to retrieve a specific field.
6+
7+
#### Adding custom metadata
8+
9+
To attach custom metadata for a field, use the `@Extensions()` decorator exported from the `@nestjs/graphql` package.
10+
11+
```typescript
12+
@Field()
13+
@Extensions({ role: Role.ADMIN })
14+
password: string;
15+
```
16+
17+
In the example above, we assigned the `role` metadata property the value of `Role.ADMIN`. `Role` is a simple TypeScript enum that groups all the user roles available in our system.
18+
19+
Note, in addition to setting metadata on fields, you can use the `@Extensions()` decorator at the class level and method level (e.g., on the query handler).
20+
21+
#### Using custom metadata
22+
23+
The logic that leverages the custom metatada can be as complex as needed. For example, you can create a simple interceptor that stores/logs events per method invocation, or create a sophisticated guard that **analyzes requested fields**, iterates through the `GraphQLObjectType` definition, and matches the roles required to retrieve specific fields with the caller permissions (field-level permissions system).
24+
25+
Let's define a `FieldRolesGuard` that implements a basic version of such a field-level permissions system.
26+
27+
```typescript
28+
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
29+
import { GqlExecutionContext } from '@nestjs/graphql';
30+
import { GraphQLNonNull, GraphQLObjectType, GraphQLResolveInfo } from 'graphql';
31+
import * as graphqlFields from 'graphql-fields';
32+
33+
@Injectable()
34+
export class FieldRolesGuard implements CanActivate {
35+
canActivate(context: ExecutionContext): boolean {
36+
const info = GqlExecutionContext.create(context).getInfo<
37+
GraphQLResolveInfo
38+
>();
39+
const returnType = (info.returnType instanceof GraphQLNonNull
40+
? info.returnType.ofType
41+
: info.returnType) as GraphQLObjectType;
42+
43+
const fields = returnType.getFields();
44+
const requestedFields = graphqlFields(info);
45+
46+
Object.entries(fields)
47+
.filter(([key]) => key in requestedFields)
48+
.map(([_, field]) => field)
49+
.filter((field) => field.extensions && field.extensions.role)
50+
.forEach((field) => {
51+
// match user and field roles here
52+
console.log(field.extensions.role);
53+
});
54+
55+
return true;
56+
}
57+
}
58+
```
59+
60+
> warning **Warning** For illustration purposes, we assumed that **every** resolver returns either the `GraphQLObjectType` or `GraphQLNonNull` that wraps the object type. In a real-world application, you should cover other cases (scalars, etc.). Note that using this particular implementation can lead to unexpected errors (e.g., missing `getFields()` method).
61+
62+
In the example above, we've used the [graphql-fields](https://github.com/robrichard/graphql-fields) package that turns the `GraphQLResolveInfo` object into an object that consists of the requested fields. We used this specific library to make the presented example somewhat simpler.
63+
64+
With this guard in place, if the return type of any resolver contains a field annotated with the `@Extensions({{ '{' }} role: Role.ADMIN {{ '}' }}})` decorator, this `role` (`Role.ADMIN`) will be logged in the console **if requested** in the GraphQL query.

content/graphql/quick-start.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ In this chapter, we assume a basic understanding of GraphQL, and focus on how to
99
Start by installing the required packages:
1010

1111
```bash
12-
$ npm i --save @nestjs/graphql graphql-tools graphql
12+
$ npm i @nestjs/graphql graphql-tools graphql
1313
```
1414

1515
Depending on what underlying platform you use (Express or Fastify), you must also install either `apollo-server-express` or `apollo-server-fastify`.
@@ -169,6 +169,24 @@ definitionsFactory.generate({
169169
});
170170
```
171171

172+
To automatically generate the additional `__typename` field for every object type, enable the `emitTypenameField` option.
173+
174+
```typescript
175+
definitionsFactory.generate({
176+
// ...,
177+
emitTypenameField: true,
178+
});
179+
```
180+
181+
To generate resolvers (queries, mutations, subscriptions) as plain fields without arguments, enable the `skipResolverArgs` option.
182+
183+
```typescript
184+
definitionsFactory.generate({
185+
// ...,
186+
skipResolverArgs: true,
187+
});
188+
```
189+
172190
A fully working schema first sample is available [here](https://github.com/nestjs/nest/tree/master/sample/12-graphql-schema-first).
173191

174192
#### Accessing generated schema

0 commit comments

Comments
 (0)