Skip to content

Commit 32903e2

Browse files
2 parents c94040d + 107dcb2 commit 32903e2

File tree

16 files changed

+217
-18
lines changed

16 files changed

+217
-18
lines changed

content/controllers.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,7 @@ export class CatsController {
550550
}
551551
```
552552
553-
Though this approach works, and does in fact allow for more flexibility in some ways by providing full control of the response object (headers manipulation, library-specific features, and so on), it should be used with care. In general, the approach is much less clear and does have some disadvantages. The main disadvantage is that your code become platform-dependent (as underlying libraries may have different APIs on the response object), and harder to test (you'll have to mock the response object, etc.).
553+
Though this approach works, and does in fact allow for more flexibility in some ways by providing full control of the response object (headers manipulation, library-specific features, and so on), it should be used with care. In general, the approach is much less clear and does have some disadvantages. The main disadvantage is that your code becomes platform-dependent (as underlying libraries may have different APIs on the response object), and harder to test (you'll have to mock the response object, etc.).
554554
555555
Also, in the example above, you lose compatibility with Nest features that depend on Nest standard response handling, such as Interceptors and `@HttpCode()` / `@Header()` decorators. To fix this, you can set the `passthrough` option to `true`, as follows:
556556

content/fundamentals/unit-testing.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ providers: [
349349
{
350350
provide: APP_GUARD,
351351
useExisting: JwtAuthGuard,
352+
// ^^^^^^^^ notice the use of 'useExisting' instead of 'useClass'
352353
},
353354
JwtAuthGuard,
354355
],

content/graphql/resolvers-map.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ type Author {
1717
id: Int!
1818
firstName: String
1919
lastName: String
20-
posts: [Post]
20+
posts: [Post!]!
2121
}
2222
```
2323

@@ -57,7 +57,7 @@ type Author {
5757
id: Int!
5858
firstName: String
5959
lastName: String
60-
posts: [Post]
60+
posts: [Post!]!
6161
}
6262
```
6363

content/recipes/mikroorm.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ export class AppModule {}
233233

234234
// register the request context middleware
235235
const app = await NestFactory.create(AppModule, { ... });
236+
const orm = app.get(MikroORM);
236237

237238
app.use((req, res, next) => {
238239
storage.run(orm.em.fork(true, true), next);

content/recipes/nest-commander.md

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
### Nest Commander
2+
3+
Expanding on the [standalone application](/standalone-applications) docs there's also the [nest-commander](https://jmcdo29.github.io/nest-commander) package for writing command line applications in a structure similar to your typical Nest application.
4+
5+
> info **info** `nest-commander` is a third party package and is not managed by the entirety of the NestJS core team. Please, report any issues found with the library in the [appropriate repository](https://github.com/jmcdo29/nest-commander/issues/new/choose)
6+
7+
#### Installation
8+
9+
Just like any other package, you've got to install it before you can use it.
10+
11+
```bash
12+
$ npm i nest-commander
13+
```
14+
15+
#### A Command file
16+
17+
`nest-commander` makes it easy to write new command-line applications with [decorators](https://www.typescriptlang.org/docs/handbook/decorators.html) via the `@Command()` decorator for classes and the `@Option()` decorator for methods of that class. Every command file should implement the `CommandRunner` interface and should be decorated with a `@Command()` decorator.
18+
19+
Every command is seen as an `@Injectable()` by Nest, so your normal Dependency Injection still works as you would expect it to. The only thing to take note of is the interface `CommandRunner`, which should be implemented by each command. The `CommandRunner` interface ensures that all commands have a `run` method that returns a `Promise<void>` and takes in the parameters `string[], Record<string, any>`. The `run` command is where you can kick all of your logic off from, it will take in whatever parameters did not match option flags and pass them in as an array, just in case you are really meaning to work with multiple parameters. As for the options, the `Record<string, any>`, the names of these properties match the `name` property given to the `@Option()` decorators, while their value matches the return of the option handler. If you'd like better type safety, you are welcome to create an interface for your options as well.
20+
21+
#### Running the Command
22+
23+
Similar to how in a NestJS application we can use the `NestFactory` to create a server for us, and run it using `listen`, the `nest-commander` package exposes a simple to use API to run your server. Import the `CommandFactory` and use the `static` method `run` and pass in the root module of your application. This would probably look like below
24+
25+
```ts
26+
import { CommandFactory } from 'nest-commander';
27+
import { AppModule } from './app.module';
28+
29+
async function bootstrap() {
30+
await CommandFactory.run(AppModule);
31+
}
32+
33+
bootstrap();
34+
```
35+
36+
By default, Nest's logger is disabled when using the `CommandFactory`. It's possible to provide it though, as the second argument to the `run` function. You can either provide a custom NestJS logger, or an array of log levels you want to keep - it might be useful to at least provide `['error']` here, if you only want to print out Nest's error logs.
37+
38+
```ts
39+
import { CommandFactory } from 'nest-commander';
40+
import { AppModule } from './app.module';
41+
import { LogService } './log.service';
42+
43+
async function bootstrap() {
44+
await CommandFactory.run(AppModule, new LogService());
45+
46+
// or, if you only want to print Nest's warnings and errors
47+
await CommandFactory.run(AppModule, ['warn', 'error']);
48+
}
49+
50+
bootstrap();
51+
```
52+
53+
And that's it. Under the hood, `CommandFactory` will worry about calling `NestFactory` for you and calling `app.close()` when necessary, so you shouldn't need to worry about memory leaks there. If you need to add in some error handling, there's always `try/catch` wrapping the `run` command, or you can chain on some `.catch()` method to the `bootstrap()` call.
54+
55+
#### Testing
56+
57+
So what's the use of writing a super awesome command line script if you can't test it super easily, right? Fortunately, `nest-commander` has some utilities you can make use of that fits in perfectly with the NestJS ecosystem, it'll feel right at home to any Nestlings out there. Instead of using the `CommandFactory` for building the command in test mode, you can use `CommandTestFactory` and pass in your metadata, very similarly to how `Test.createTestingModule` from `@nestjs/testing` works. In fact, it uses this package under the hood. You're also still able to chain on the `overrideProvider` methods before calling `compile()` so you can swap out DI pieces right in the test.
58+
59+
#### Putting it all together
60+
61+
The following class would equate to having a CLI command that can take in the subcommand `basic` or be called directly, with `-n`, `-s`, and `-b` (along with their long flags) all being supported and with custom parsers for each option. The `--help` flag is also supported, as is customary with commander.
62+
63+
```ts
64+
import { Command, CommandRunner, Option } from 'nest-commander';
65+
import { LogService } from './log.service';
66+
67+
interface BasicCommandOptions {
68+
string?: string;
69+
boolean?: boolean;
70+
number?: number;
71+
}
72+
73+
@Command({ name: 'basic', description: 'A parameter parse' })
74+
export class BasicCommand implements CommandRunner {
75+
constructor(private readonly logService: LogService) {}
76+
77+
async run(
78+
passedParam: string[],
79+
options?: BasicCommandOptions,
80+
): Promise<void> {
81+
if (options?.boolean !== undefined && options?.boolean !== null) {
82+
this.runWithBoolean(passedParam, options.boolean);
83+
} else if (options?.number) {
84+
this.runWithNumber(passedParam, options.number);
85+
} else if (options?.string) {
86+
this.runWithString(passedParam, options.string);
87+
} else {
88+
this.runWithNone(passedParam);
89+
}
90+
}
91+
92+
@Option({
93+
flags: '-n, --number [number]',
94+
description: 'A basic number parser',
95+
})
96+
parseNumber(val: string): number {
97+
return Number(val);
98+
}
99+
100+
@Option({
101+
flags: '-s, --string [string]',
102+
description: 'A string return',
103+
})
104+
parseString(val: string): string {
105+
return val;
106+
}
107+
108+
@Option({
109+
flags: '-b, --boolean [boolean]',
110+
description: 'A boolean parser',
111+
})
112+
parseBoolean(val: string): boolean {
113+
return JSON.parse(val);
114+
}
115+
116+
runWithString(param: string[], option: string): void {
117+
this.logService.log({ param, string: option });
118+
}
119+
120+
runWithNumber(param: string[], option: number): void {
121+
this.logService.log({ param, number: option });
122+
}
123+
124+
runWithBoolean(param: string[], option: boolean): void {
125+
this.logService.log({ param, boolean: option });
126+
}
127+
128+
runWithNone(param: string[]): void {
129+
this.logService.log({ param });
130+
}
131+
}
132+
```
133+
134+
Make sure the command class is added to a module
135+
136+
```ts
137+
@Module({
138+
providers: [LogService, BasicCommand],
139+
})
140+
export class AppModule {}
141+
```
142+
143+
And now to be able to run the CLI in your main.ts you can do the following
144+
145+
```ts
146+
async function bootstrap() {
147+
await CommandFactory.run(AppModule);
148+
}
149+
150+
bootstrap();
151+
```
152+
153+
And just like that, you've got a command line application.
154+
155+
#### More Information
156+
157+
Visit the [nest-commander docs site](https://jmcdo29.github.io/nest-commander) for more information, examples, and API documentation.

content/recipes/prisma.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ When setting up your NestJS application, you'll want to abstract away the Prisma
247247
Inside the `src` directory, create a new file called `prisma.service.ts` and add the following code to it:
248248

249249
```typescript
250-
import { INestApplication, Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
250+
import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
251251
import { PrismaClient } from '@prisma/client';
252252

253253
@Injectable()
@@ -530,12 +530,13 @@ Prisma interferes with NestJS `enableShutdownHooks`. Prisma listens for shutdown
530530
...
531531
import { PrismaService } from './services/prisma/prisma.service';
532532
...
533-
bootstrap() {
533+
async function bootstrap() {
534534
...
535535
const prismaService: PrismaService = app.get(PrismaService);
536536
prismaService.enableShutdownHooks(app)
537537
...
538538
}
539+
bootstrap()
539540
```
540541

541542
You can [read more](https://github.com/prisma/prisma/issues/2917#issuecomment-708340112) about Prisma handling of shutdown signal, and `beforeExit` event.

content/recipes/sql-typeorm.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
To start the adventure with this library we have to install all required dependencies:
1212

1313
```bash
14-
$ npm install --save typeorm mysql
14+
$ npm install --save typeorm mysql2
1515
```
1616

1717
The first step we need to do is to establish the connection with our database using `createConnection()` function imported from the `typeorm` package. The `createConnection()` function returns a `Promise`, and therefore we have to create an [async provider](/fundamentals/async-components).

content/techniques/caching.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ export class AppModule {}
118118

119119
#### Customize caching
120120

121-
All cached data has its own expiration time (TTL). To customize default values, pass the options object to the `register()` method.
121+
All cached data has its own expiration time ([TTL](https://en.wikipedia.org/wiki/Time_to_live)). To customize default values, pass the options object to the `register()` method.
122122

123123
```typescript
124124
CacheModule.register({
@@ -127,6 +127,16 @@ CacheModule.register({
127127
});
128128
```
129129

130+
#### Use module globally
131+
132+
When you want to use `CacheModule` in other modules, you'll need to import it (as is standard with any Nest module). Alternatively, declare it as a [global module](https://docs.nestjs.com/modules#global-modules) by setting the options object's `isGlobal` property to `true`, as shown below. In that case, you will not need to import `CacheModule` in other modules once it's been loaded in the root module (e.g., `AppModule`).
133+
134+
```typescript
135+
CacheModule.register({
136+
isGlobal: true,
137+
});
138+
```
139+
130140
#### Global cache overrides
131141

132142
While global cache is enabled, cache entries are stored under a `CacheKey` that is auto-generated based on the route path. You may override certain cache settings (`@CacheKey()` and `@CacheTTL()`) on a per-method basis, allowing customized caching strategies for individual controller methods. This may be most relevant while using [different cache stores.](https://docs.nestjs.com/techniques/caching#different-stores)

content/techniques/queues.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ The construction above will instantiate `BullConfigService` inside `BullModule`
447447
```typescript
448448
@Injectable()
449449
class BullConfigService implements SharedBullConfigurationFactory {
450-
createSharedConfiguration(): SharedBullConfigurationFactory {
450+
createSharedConfiguration(): BullModuleOptions {
451451
return {
452452
redis: {
453453
host: 'localhost',
Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
<div class="social-wrapper">
2-
<a href="https://twitter.com/nestframework" target="_blank">
2+
<a href="https://twitter.com/nestframework"
3+
title="Twitter account"
4+
target="_blank">
35
<i class="fab fa-twitter"></i>
46
</a>
5-
<a href="https://github.com/nestjs/nest" target="_blank">
7+
<a href="https://github.com/nestjs/nest"
8+
title="Github repository"
9+
target="_blank">
610
<i class="fab fa-github"></i>
711
</a>
8-
<a href="https://stackoverflow.com/questions/tagged/nestjs" target="_blank">
12+
<a href="https://stackoverflow.com/questions/tagged/nestjs"
13+
title="Stackoverflow"
14+
target="_blank">
915
<i class="fab fa-stack-overflow"></i>
1016
</a>
1117
<a
@@ -15,7 +21,10 @@
1521
>
1622
<i class="fa fa-globe"></i>
1723
</a>
18-
<a href="https://discord.gg/G7Qnnhy" target="_blank" rel="nofollow">
24+
<a href="https://discord.gg/G7Qnnhy"
25+
title="Discord"
26+
target="_blank"
27+
rel="nofollow">
1928
<i class="fab fa-discord"></i>
2029
</a>
2130
</div>

0 commit comments

Comments
 (0)