Skip to content

Commit daa02f1

Browse files
Merge pull request #1139 from johnbiundo/biundo/graphql-mapped-types
Biundo/graphql mapped types
2 parents b7f67c0 + dce0c48 commit daa02f1

22 files changed

+122
-71
lines changed

content/cli/usages.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ $ nest g <schematic> <name> [options]
5555

5656
| Name | Alias | Description |
5757
| ------------- | ----- | --------------------------------------------------------------------------------------------------- |
58-
| `application` | | Generate a new application within a monorepo (converting to monorepo if it's a standard structure). |
58+
| `app` | | Generate a new application within a monorepo (converting to monorepo if it's a standard structure). |
5959
| `library` | `lib` | Generate a new library within a monorepo (converting to monorepo if it's a standard structure). |
6060
| `class` | `cl` | Generate a new class. |
6161
| `controller` | `co` | Generate a controller declaration. |

content/cli/workspaces.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ The `generate app` schematic has reorganized the code - moving each **applicatio
9393
9494
#### Workspace projects
9595

96-
A mono repo uses the concept of a workspace to manage its member entities. Workspaces are composed of **projects**. A project may be either:
96+
A monorepo uses the concept of a workspace to manage its member entities. Workspaces are composed of **projects**. A project may be either:
9797

9898
- an **application**: a full Nest application including a `main.ts` file to bootstrap the application. Aside from compile and build considerations, an application-type project within a workspace is functionally identical to an application within a _standard mode_ structure.
9999
- a **library**: a library is a way of packaging a general purpose set of features (modules, providers, controllers, etc.) that can be used within other projects. A library cannot run on its own, and has no `main.ts` file. Read more about libraries [here](/cli/libraries).

content/discover/who-uses.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,11 @@
141141
"logo": "/assets/logo/zeoagency.svg",
142142
"url": "https://zeo.org/tr/",
143143
"width": "80px"
144+
},
145+
{
146+
"logo": "/assets/logo/valueadd.png",
147+
"url": "https://valueadd.pl/",
148+
"width": "120px"
144149
}
145150
],
146151
"Body": [

content/faq/hybrid-application.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
### Hybrid application
22

3-
A hybrid application is one that both listens for HTTP requests, as well as makes use of connected microservices. The `INestApplication` instance can be connected with `INestMicroservice` instances through the `connectMicroservice()` method. To connect multiple microservice instances, simply pass additional microservice configuration objects as arguments in a comma-separated list.
3+
A hybrid application is one that both listens for HTTP requests, as well as makes use of connected microservices. The `INestApplication` instance can be connected with `INestMicroservice` instances through the `connectMicroservice()` method.
44

55
```typescript
66
const app = await NestFactory.create(AppModule);
@@ -11,3 +11,26 @@ const microservice = app.connectMicroservice({
1111
await app.startAllMicroservicesAsync();
1212
await app.listen(3001);
1313
```
14+
15+
To connect multiple microservice instances, issue the call to `connectMicroservice()` for each microservice:
16+
17+
```typescript
18+
const app = await NestFactory.create(AppModule);
19+
// microservice #1
20+
const microserviceTcp = app.connectMicroservice<MicroserviceOptions>({
21+
transport: Transport.TCP,
22+
options: {
23+
port: 3001,
24+
},
25+
});
26+
// microservice #2
27+
const microserviceRedis = app.connectMicroservice<MicroserviceOptions>({
28+
transport: Transport.REDIS,
29+
options: {
30+
url: 'redis://localhost:6379',
31+
},
32+
});
33+
34+
await app.startAllMicroservicesAsync();
35+
await app.listen(3001);
36+
```

content/fundamentals/dependency-injection.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ export class AppModule {}
272272

273273
#### Alias providers: `useExisting`
274274

275-
The `useExisting` syntax allows you to create aliases for existing providers. This creates two ways to access the same provider. In the example below, the (string-based) token `'AliasedLoggerService'` is an alias for the (class-based) token `LoggerService`. Assume we have two different dependencies, one for `'AlilasedLoggerService'` and one for `LoggerService`. If both dependencies are specified with `SINGLETON` scope, they'll both resolve to the same instance.
275+
The `useExisting` syntax allows you to create aliases for existing providers. This creates two ways to access the same provider. In the example below, the (string-based) token `'AliasedLoggerService'` is an alias for the (class-based) token `LoggerService`. Assume we have two different dependencies, one for `'AliasedLoggerService'` and one for `LoggerService`. If both dependencies are specified with `SINGLETON` scope, they'll both resolve to the same instance.
276276

277277
```typescript
278278
@Injectable()

content/fundamentals/execution-context.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,17 @@ The `ArgumentsHost` class provides methods for retrieving the arguments being pa
1515
When building generic [guards](/guards), [filters](/exception-filters), and [interceptors](/interceptors) which are meant to run across multiple application contexts, we need a way to determine the type of application that our method is currently running in. Do this with the `getType()` method of `ArgumentsHost`:
1616

1717
```typescript
18-
const type = host.getType();
19-
if (type === 'http') {
20-
// HTTP application
21-
} else if (type === 'rpc') {
22-
// Microservice
18+
if (host.getType() === 'http') {
19+
// do something that is only important in the context of regular HTTP requests (REST)
20+
} else if (host.getType() === 'rpc') {
21+
// do something that is only important in the context of Microservice requests
22+
} else if (host.getType<GqlContextType>() === 'graphql') {
23+
// do something that is only important in the context of GraphQL requests
2324
}
2425
```
2526

27+
> info **Hint** The `GqlContextType` is imported from the `@nestjs/graphql` package.
28+
2629
With the application type available, we can write more generic components, as shown below.
2730

2831
#### Host handler arguments

content/graphql/enums.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,7 @@ Sometimes a backend forces a different value for an enum internally than in the
6969
```typescript
7070
@Resolver('AllowedColor')
7171
export class AllowedColorResolver {
72-
@ResolveField('RED')
73-
getRedColor() {
74-
return '#f00';
75-
}
72+
[AllowedColor.RED]: '#f00';
7673
}
7774
```
7875

content/graphql/mapped-types.md

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
### Mapped types
22

3-
##### This chapter applies only to code first approach
3+
> warning **Warning** This chapter applies only to the code first approach.
44
5-
A common task is to take an existing type and make each of its properties optional. This happens often enough that NestJS provides a way to create new types based on old types — mapped types.
5+
As you build out features like CRUD (Create/Read/Update/Delete) it's often useful to construct variants on a base entity type. Nest provides several utility functions that perform type transformations to make this task more convenient.
66

77
#### Partial
88

9-
Make all properties of a type optional.
9+
When building input validation types (also called DTOs), it's often useful to build **create** and **update** variations on the same type. For example, the **create** variant may require all fields, while the **update** variant may make all fields optional.
1010

11-
Original type:
11+
Nest provides the `PartialType()` utility function to make this task easier and minimize boilerplate.
12+
13+
The `PartialType()` function returns a type (class) with all the properties of the input type set to optional. For example, suppose we have a **create** type as follows:
1214

1315
```typescript
1416
@InputType()
@@ -24,7 +26,7 @@ class CreateUserInput {
2426
}
2527
```
2628

27-
Mapped type:
29+
By default, all of these fields are required. To create a type with the same fields, but with each one optional, use `PartialType()` passing the class reference (`CreateUserInput`) as an argument:
2830

2931
```typescript
3032
@InputType()
@@ -33,13 +35,16 @@ export class UpdateUserInput extends PartialType(CreateUserInput) {}
3335

3436
> info **Hint** The `PartialType()` function is imported from the `@nestjs/graphql` package.
3537
36-
> warning **Warning** If you want to create an `InputType` based on the `ObjectType`, you must explicitly specify it in the function, as follows: `PartialType(CreateUserInput, InputType)` where `InputType` is a reference to a decorator factory.
38+
The `PartialType()` function takes an optional second argument that is a reference to the decorator factory of the type being extended. In the example above, we are extending `CreateUserInput` which is annotated with the `@InputType()` decorator. We didn't need to pass `InputType` as the second argument since it's the default value. If you want to extend a class decorated with `@ObjectType`, pass `ObjectType` as the second argument. For example:
3739

38-
#### Pick
40+
```typescript
41+
@InputType()
42+
export class UpdateUserInput extends PartialType(User, ObjectType) {}
43+
```
3944

40-
Constructs a type by picking the set of properties from type.
45+
#### Pick
4146

42-
Original type:
47+
The `PickType()` function constructs a new type (class) by picking a set of properties from an input type. For example, suppose we start with a type like:
4348

4449
```typescript
4550
@InputType()
@@ -55,7 +60,7 @@ class CreateUserInput {
5560
}
5661
```
5762

58-
Mapped type:
63+
We can pick a set of properties from this class using the `PickType()` utility function:
5964

6065
```typescript
6166
@InputType()
@@ -64,11 +69,9 @@ export class UpdateEmailInput extends PickType(CreateUserInput, ['email']) {}
6469

6570
> info **Hint** The `PickType()` function is imported from the `@nestjs/graphql` package.
6671
67-
#### Pick
68-
69-
Constructs a type by picking all properties from type and then removing particular set of keys.
72+
#### Omit
7073

71-
Original type:
74+
The `OmitType()` function constructs a type by picking all properties from an input type and then removing a particular set of keys. For example, suppose we start with a type like:
7275

7376
```typescript
7477
@InputType()
@@ -84,7 +87,7 @@ class CreateUserInput {
8487
}
8588
```
8689

87-
Mapped type:
90+
We can generate a derived type that has every property **except** `email` as shown below. In this construct, the second argument to `OmitType` is an array of property names.
8891

8992
```typescript
9093
@InputType()
@@ -95,13 +98,11 @@ export class UpdateUserInput extends OmitType(CreateUserInput, ['email']) {}
9598
9699
#### Composition
97100

98-
Mapped types are composeable.
99-
100-
Example:
101+
The type mapping utility functions are composable. For example, the following will produce a type (class) that has all of the properties of the `CreateUserInput` type except for `email`, and those properties will be set to optional:
101102

102103
```typescript
103104
@InputType()
104-
export class UpdateUserInput extends Partial(
105+
export class UpdateUserInput extends PartialType(
105106
OmitType(CreateUserInput, ['email']),
106107
) {}
107108
```

content/graphql/mutations.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ async upvotePost(
5050
) {}
5151
```
5252

53-
// Should we add note about Inheritance here? (input types inheritance)
54-
5553
#### Schema first
5654

5755
Let's extend our `AuthorResolver` used in the previous section (see [resolvers](/graphql/resolvers)).

content/graphql/quick-start.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,13 +173,15 @@ A fully working schema first sample is available [here](https://github.com/nestj
173173

174174
#### Accessing generated schema
175175

176-
To access the generated schema (in either code first or schema first approach), use the `GraphQLHost` class:
176+
In some circumstances (for example end-to-end tests), you may want to get a reference to the generated schema object. In end-to-end tests, you can then run queries using the `graphql` object without using any HTTP listeners.
177+
178+
You can access the generated schema (in either the code first or schema first approach), using the `GraphQLSchemaHost` class:
177179

178180
```typescript
179181
const { schema } = app.get(GraphQLSchemaHost);
180182
```
181183

182-
> info **Hint** Make sure to call the `GraphQLSchemaHost#schema` getter when the application is already initialized (after the `onModuleInit` hook triggered by either `app.listen()` or `app.init()` method.
184+
> info **Hint** You must call the `GraphQLSchemaHost#schema` getter after the application has been initialized (after the `onModuleInit` hook has been triggered by either the `app.listen()` or `app.init()` method).
183185
184186
#### Async configuration
185187

0 commit comments

Comments
 (0)