Skip to content

Commit bdf6ebe

Browse files
2 parents e1815e6 + 36253d3 commit bdf6ebe

File tree

9 files changed

+546
-411
lines changed

9 files changed

+546
-411
lines changed

content/fundamentals/unit-testing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ The compiled module has several useful methods, as described in the following ta
302302
303303
#### Testing request-scoped instances
304304

305-
[Request-scoped](/fundamentals/injection-scope) providers are created uniquely for each incoming **request**. The instance is garbage-collected after the request has completed processing. This poses a problem, because we can't access a dependency injection sub-tree generated specifically for a tested request.
305+
[Request-scoped](/fundamentals/injection-scopes) providers are created uniquely for each incoming **request**. The instance is garbage-collected after the request has completed processing. This poses a problem, because we can't access a dependency injection sub-tree generated specifically for a tested request.
306306

307307
We know (based on the sections above) that the `resolve()` method can be used to retrieve a dynamically instantiated class. Also, as described <a href="https://docs.nestjs/com/fundamentals/module-ref#resolving-scoped-providers">here</a>, we know we can pass a unique context identifier to control the lifecycle of a DI container sub-tree. How do we leverage this in a testing context?
308308

content/graphql/quick-start.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
### Quick start
1+
## Harnessing the power of TypeScript & GraphQL
22

3-
GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. It's an elegant approach that solves many problems typically found with REST APIs. For background, we suggest reading this [comparison](https://dev-blog.apollodata.com/graphql-vs-rest-5d425123e34b) between GraphQL and REST. In this chapter, we assume a basic understanding of GraphQL, and focus on how to work with the built-in `@nestjs/graphql` module.
3+
[GraphQL](https://graphql.org/) is a powerful query language for APIs and a runtime for fulfilling those queries with your existing data. It's an elegant approach that solves many problems typically found with REST APIs. For background, we suggest reading this [comparison](https://dev-blog.apollodata.com/graphql-vs-rest-5d425123e34b) between GraphQL and REST.
44

5-
The `GraphQLModule` is a wrapper around the [Apollo](https://www.apollographql.com/) server. We use this proven GraphQL package to provide a way to use GraphQL with Nest.
5+
GraphQL combined with [TypeScript](https://www.typescriptlang.org/) helps you develop better type safety with your GraphQL queries, giving you get end-to-end typing.
6+
7+
In this chapter, we assume a basic understanding of GraphQL, and focus on how to work with the built-in `@nestjs/graphql` module. The `GraphQLModule` is a wrapper around the [Apollo](https://www.apollographql.com/) server. We use this proven GraphQL package to provide a way to use GraphQL with Nest.
68

79
#### Installation
810

@@ -22,7 +24,7 @@ In the **schema first** approach, the source of truth is a GraphQL SDL (Schema D
2224

2325
In the **code first** approach, you use decorators and TypeScript classes to generate the corresponding GraphQL schema. This approach is useful if you prefer to work exclusively with TypeScript and avoid context switching between language syntaxes.
2426

25-
#### Getting started
27+
#### Getting started with GraphQL & TypeScript
2628

2729
Once the packages are installed, we can import the `GraphQLModule` and configure it with the `forRoot()` static method.
2830

content/microservices/grpc.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ export class HeroController {
161161
@@switch
162162
@Controller()
163163
export class HeroController {
164-
@GrpcMethod('HeroService)
164+
@GrpcMethod('HeroService')
165165
findOne(data, metadata) {
166166
const items = [
167167
{ id: 1, name: 'John' },

content/microservices/kafka.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,16 @@ The `options` property is specific to the chosen transporter. The <strong>Kafka<
7171
>here</a
7272
>)</td>
7373
</tr>
74+
<tr>
75+
<td><code>subscribe</code></td>
76+
<td>Subscribe configuration options (read more
77+
<a
78+
href="https://kafka.js.org/docs/consuming#frombeginning"
79+
rel="nofollow"
80+
target="blank"
81+
>here</a
82+
>)</td>
83+
</tr>
7484
<tr>
7585
<td><code>producer</code></td>
7686
<td>Producer configuration options (read more

content/recipes/swagger.md

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ Once the installation process is complete, open the `main.ts` file and initializ
2323
```typescript
2424
import { NestFactory } from '@nestjs/core';
2525
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
26-
import { ApplicationModule } from './app.module';
26+
import { AppModule } from './app.module';
2727

2828
async function bootstrap() {
29-
const app = await NestFactory.create(ApplicationModule);
29+
const app = await NestFactory.create(AppModule);
3030

3131
const options = new DocumentBuilder()
3232
.setTitle('Cats example')
@@ -158,6 +158,80 @@ With `isArray` set to **true**, the `enum` can be selected as a **multi-select**
158158

159159
<figure><img src="/assets/enum_query_array.gif" /></figure>
160160

161+
#### Enums schema
162+
163+
By default, the `enum` property will add a raw definition of [Enum](https://swagger.io/docs/specification/data-models/enums/) on the `parameter`.
164+
165+
```yaml
166+
CatDetail:
167+
type: 'object'
168+
properties:
169+
...
170+
- breed:
171+
type: 'string'
172+
enum:
173+
- Persian
174+
- Tabby
175+
- Siamese
176+
```
177+
178+
The above specification works fine for most cases. However, if you are utilizing a tool that takes the specification as **input** and generates **client-side** code, you might run into a problem with the generated code containing duplicated `enums`. Consider the following code snippet:
179+
180+
```typescript
181+
// generated client-side code
182+
export class CatDetail {
183+
breed: CatDetailEnum;
184+
}
185+
186+
export class CatInformation {
187+
breed: CatInformationEnum;
188+
}
189+
190+
export enum CatDetailEnum {
191+
Persian = 'Persian',
192+
Tabby = 'Tabby',
193+
Siamese = 'Siamese'
194+
}
195+
196+
export enum CatInformationEnum {
197+
Persian = 'Persian',
198+
Tabby = 'Tabby',
199+
Siamese = 'Siamese'
200+
}
201+
```
202+
203+
> info **Hint** The above snippet is generated using a tool called [NSwag](https://github.com/RicoSuter/NSwag).
204+
205+
You can see that now you have two `enums` that are exactly the same.
206+
To address this issue, you can pass an `enumName` next to `enum` property in your decorator.
207+
208+
```typescript
209+
export class CatDetail {
210+
@ApiProperty({ enum: CatBreed, enumName: 'CatBreed' })
211+
breed: CatBreed;
212+
}
213+
```
214+
215+
`enumName` enables `nestjs/swagger` to turn `CatBreed` into its own `schema` which in turns makes `CatBreed` reusable. The specification will look like the following:
216+
217+
```yaml
218+
CatDetail:
219+
type: 'object'
220+
properties:
221+
...
222+
- breed:
223+
schema:
224+
$ref: '#/components/schemas/CatBreed'
225+
CatBreed:
226+
type: string
227+
enum:
228+
- Persian
229+
- Tabby
230+
- Siamese
231+
```
232+
233+
> info **Hint** Any **decorator** that takes `enum` as a property will also take `enumName`.
234+
161235
#### Arrays
162236

163237
When the property is an array, we must manually indicate the array type as shown below:
@@ -279,10 +353,10 @@ You can setup multiple specifications support as shown below:
279353
```typescript
280354
import { NestFactory } from '@nestjs/core';
281355
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
282-
import { ApplicationModule } from './app.module';
356+
import { AppModule } from './app.module';
283357
284358
async function bootstrap() {
285-
const app = await NestFactory.create(ApplicationModule);
359+
const app = await NestFactory.create(AppModule);
286360
287361
/**
288362
* createDocument(application, configurationOptions, extraOptions);
@@ -548,6 +622,14 @@ class FileUploadDto {
548622
}
549623
```
550624

625+
#### Extensions
626+
627+
To add an Extension to a request use the `@ApiExtension()` decorator. The extension name must be prefixed with `x-`.
628+
629+
```typescript
630+
@ApiExtension('x-foo', { hello: 'world' })
631+
```
632+
551633
#### Decorators
552634

553635
All of the available OpenAPI decorators have an `Api` prefix to distinguish them from the core decorators. Below is a full list of the exported decorators along with a designation of the level at which the decorator may be applied.
@@ -572,6 +654,7 @@ All of the available OpenAPI decorators have an `Api` prefix to distinguish them
572654
| `@ApiProperty()` | Model |
573655
| `@ApiPropertyOptional()` | Model |
574656
| `@ApiHideProperty()` | Model |
657+
| `@ApiExtension()` | Method |
575658

576659
#### Plugin
577660

content/techniques/file-upload.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ MulterModule.register({
122122
});
123123
```
124124

125+
> info **Hint** The `MulterModule` class is exported from the `@nestjs/platform-express` package.
126+
125127
#### Async configuration
126128

127129
When you need to set `MulterModule` options asynchronously instead of statically, use the `registerAsync()` method. As with most dynamic modules, Nest provides several techniques to deal with async configuration.

content/techniques/sql.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -614,13 +614,13 @@ Our factory behaves like any other [asynchronous provider](https://docs.nestjs.c
614614
```typescript
615615
TypeOrmModule.forRootAsync({
616616
imports: [ConfigModule],
617-
useFactory: async (configService: ConfigService) => ({
617+
useFactory: (configService: ConfigService) => ({
618618
type: 'mysql',
619-
host: configService.getString('HOST'),
620-
port: configService.getString('PORT'),
621-
username: configService.getString('USERNAME'),
622-
password: configService.getString('PASSWORD'),
623-
database: configService.getString('DATABASE'),
619+
host: configService.get<string>('HOST'),
620+
port: configService.get<string>('PORT'),
621+
username: configService.get<string>('USERNAME'),
622+
password: configService.get<string>('PASSWORD'),
623+
database: configService.get<string>('DATABASE'),
624624
entities: [__dirname + '/**/*.entity{.ts,.js}'],
625625
synchronize: true,
626626
}),
@@ -1149,13 +1149,13 @@ Our factory behaves like any other [asynchronous provider](https://docs.nestjs.c
11491149
```typescript
11501150
SequelizeModule.forRootAsync({
11511151
imports: [ConfigModule],
1152-
useFactory: async (configService: ConfigService) => ({
1152+
useFactory: (configService: ConfigService) => ({
11531153
dialect: 'mysql',
1154-
host: configService.getString('HOST'),
1155-
port: configService.getString('PORT'),
1156-
username: configService.getString('USERNAME'),
1157-
password: configService.getString('PASSWORD'),
1158-
database: configService.getString('DATABASE'),
1154+
host: configService.get<string>('HOST'),
1155+
port: configService.get<string>('PORT'),
1156+
username: configService.get<string>('USERNAME'),
1157+
password: configService.get<string>('PASSWORD'),
1158+
database: configService.get<string>('DATABASE'),
11591159
models: [],
11601160
}),
11611161
inject: [ConfigService],

0 commit comments

Comments
 (0)