Skip to content

Commit a56d185

Browse files
docs(): minor tweaks
1 parent 6f442a0 commit a56d185

File tree

2 files changed

+79
-70
lines changed

2 files changed

+79
-70
lines changed

content/recipes/mikroorm.md

Lines changed: 47 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,19 @@
11
### MikroORM
22

3-
This recipe is here to help users getting started with MikroORM in NestJS. MikroORM is the TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. It is well maintained and the maintainer responds quick to questions and issues. It is a great alternative to TypeORM and migration from TypeORM should be fairly easy.
3+
This recipe is here to help users getting started with MikroORM in Nest. MikroORM is the TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. It is a great alternative to TypeORM and migration from TypeORM should be fairly easy. The complete documentation on MikroORM can be found [here](https://mikro-orm.io/docs).
44

5-
[The complete documentation on MikroORM can be found here.](https://mikro-orm.io/docs)
6-
7-
> info **info** @mikro-orm/nestjs is a third party package and not managed by the NestJS core team. Please bring any issues found with the library to the [appropriate repository](https://github.com/mikro-orm/nestjs)
5+
> info **info** `@mikro-orm/nestjs` is a third party package and is not managed by the NestJS core team. Please, report any issues found with the library in the [appropriate repository](https://github.com/mikro-orm/nestjs).
86
97
#### Installation
108

119
Easiest way to integrate MikroORM to Nest is via [`@mikro-orm/nestjs` module](https://github.com/mikro-orm/nestjs).
12-
Simply install it next to Nest, MikroORM and underlying driver:
10+
Simply install it next to Nest, MikroORM and underlying driver:
1311

1412
```bash
15-
$ yarn add @mikro-orm/core @mikro-orm/nestjs @mikro-orm/mysql # for mysql/mariadb
13+
$ npm i @mikro-orm/core @mikro-orm/nestjs @mikro-orm/mysql # for mysql/mariadb
1614
```
1715

18-
or
19-
20-
```bash
21-
$ npm i -s @mikro-orm/core @mikro-orm/nestjs @mikro-orm/sqlite # for sqlite
22-
```
23-
24-
MikroORM also supports `postgres` and `mongo`. See the [official docs](https://mikro-orm.io/docs/usage-with-sql/) for all the drivers.
16+
MikroORM also supports `postgres`, `sqlite`, and `mongo`. See the [official docs](https://mikro-orm.io/docs/usage-with-sql/) for all drivers.
2517

2618
Once the installation process is completed, we can import the `MikroOrmModule` into the root `AppModule`.
2719

@@ -43,7 +35,7 @@ export class AppModule {}
4335

4436
The `forRoot()` method accepts the same configuration object as `init()` from the MikroORM package. Check [this page](https://mikro-orm.io/docs/configuration) for the complete configuration documentation.
4537

46-
Alternatively we can [configure the CLI](https://mikro-orm.io/docs/installation#setting-up-the-commandline-tool) by creating a configuration file `mikro-orm.config.ts` and then call the `forRoot()` without any arguments. This won't work when you use a build tools that use tree shaking.
38+
Alternatively we can [configure the CLI](https://mikro-orm.io/docs/installation#setting-up-the-commandline-tool) by creating a configuration file `mikro-orm.config.ts` and then call the `forRoot()` without any arguments. This won't work when you use a build tools that use tree shaking.
4739

4840
```typescript
4941
@Module({
@@ -59,32 +51,29 @@ Afterward, the `EntityManager` will be available to inject across entire project
5951

6052
```ts
6153
import { MikroORM } from '@mikro-orm/core';
62-
import { EntityManager } from '@mikro-orm/mysql'; // Import EntityManager from your driver package or `@mikro-orm/knex`
54+
// Import EntityManager from your driver package or `@mikro-orm/knex`
55+
import { EntityManager } from '@mikro-orm/mysql';
6356

6457
@Injectable()
6558
export class MyService {
66-
67-
constructor(private readonly orm: MikroORM,
68-
private readonly em: EntityManager) {
69-
}
70-
59+
constructor(
60+
private readonly orm: MikroORM,
61+
private readonly em: EntityManager,
62+
) {}
7163
}
7264
```
7365

74-
> info **info** Notice that the `EntityManager` is imported from the `@mikro-orm/driver` package, where driver is `mysql`, `sqlite`, `postgres` or what driver you are using.
75-
>
76-
> In case you have `@mikro-orm/knex` installed as a dependency, you can also import the `EntityManager` from there.
66+
> info **info** Notice that the `EntityManager` is imported from the `@mikro-orm/driver` package, where driver is `mysql`, `sqlite`, `postgres` or what driver you are using. In case you have `@mikro-orm/knex` installed as a dependency, you can also import the `EntityManager` from there.
7767
7868
#### Repositories
79-
MikroORM supports the repository design pattern. For every entity we can create a repository. Read the complete [documentation on repositories here](https://mikro-orm.io/docs/repositories). To define which repositories shall be registered in the current scope you can use the `forFeature()` method. For example, in this way:
8069

81-
> info **info** You should **not** register your base entities via `forFeature()`, as there are no
82-
> repositories for those. On the other hand, base entities need to be part of the list
83-
> in `forRoot()` (or in the ORM config in general).
70+
MikroORM supports the repository design pattern. For every entity we can create a repository. Read the complete documentation on repositories [here](https://mikro-orm.io/docs/repositories). To define which repositories should be registered in the current scope you can use the `forFeature()` method. For example, in this way:
71+
72+
> info **info** You should **not** register your base entities via `forFeature()`, as there are no
73+
> repositories for those. On the other hand, base entities need to be part of the list in `forRoot()` (or in the ORM config in general).
8474
8575
```typescript
8676
// photo.module.ts
87-
8877
@Module({
8978
imports: [MikroOrmModule.forFeature([Photo])],
9079
providers: [PhotoService],
@@ -110,10 +99,8 @@ In this way we can inject the `PhotoRepository` to the `PhotoService` using the
11099
export class PhotoService {
111100
constructor(
112101
@InjectRepository(Photo)
113-
private readonly photoRepository: EntityRepository<Photo>
102+
private readonly photoRepository: EntityRepository<Photo>,
114103
) {}
115-
116-
// ...
117104
}
118105
```
119106

@@ -123,33 +110,26 @@ When using custom repositories, we can get around the need for `@InjectRepositor
123110
decorator by naming our repositories the same way as `getRepositoryToken()` method do:
124111

125112
```ts
126-
export const getRepositoryToken = <T> (entity: EntityName<T>) => `${Utils.className(entity)}Repository`;
113+
export const getRepositoryToken = <T>(entity: EntityName<T>) =>
114+
`${Utils.className(entity)}Repository`;
127115
```
128116

129117
In other words, as long as we name the repository same was as the entity is called,
130118
appending `Repository` suffix, the repository will be registered automatically in
131-
the Nest.js DI container.
132-
133-
`**./author.entity.ts**`
119+
the Nest DI container.
134120

135121
```ts
122+
// `**./author.entity.ts**`
136123
@Entity()
137124
export class Author {
138-
139125
// to allow inference in `em.getRepository()`
140126
[EntityRepositoryType]?: AuthorRepository;
141-
142127
}
143-
```
144128

145-
`**./author.repository.ts**`
146-
147-
```ts
129+
// `**./author.repository.ts**`
148130
@Repository(Author)
149131
export class AuthorRepository extends EntityRepository<Author> {
150-
151132
// your custom methods...
152-
153133
}
154134
```
155135

@@ -159,26 +139,24 @@ return, we do not need the `@InjectRepository()` decorator anymore:
159139
```ts
160140
@Injectable()
161141
export class MyService {
162-
163-
constructor(private readonly repo: AuthorRepository) { }
164-
142+
constructor(private readonly repo: AuthorRepository) {}
165143
}
166144
```
167145

168146
#### Load entities automatically
169147

170-
> info **info** `autoLoadEntities` option was added in v4.1.0
148+
> info **info** `autoLoadEntities` option was added in v4.1.0
171149
172-
Manually adding entities to the entities array of the connection options can be
173-
tedious. In addition, referencing entities from the root module breaks application
174-
domain boundaries and causes leaking implementation details to other parts of the
150+
Manually adding entities to the entities array of the connection options can be
151+
tedious. In addition, referencing entities from the root module breaks application
152+
domain boundaries and causes leaking implementation details to other parts of the
175153
application. To solve this issue, static glob paths can be used.
176154

177-
Note, however, that glob paths are not supported by webpack, so if you are building
178-
your application within a monorepo, you won't be able to use them. To address this
179-
issue, an alternative solution is provided. To automatically load entities, set the
180-
`autoLoadEntities` property of the configuration object (passed into the `forRoot()`
181-
method) to `true`, as shown below:
155+
Note, however, that glob paths are not supported by webpack, so if you are building
156+
your application within a monorepo, you won't be able to use them. To address this
157+
issue, an alternative solution is provided. To automatically load entities, set the
158+
`autoLoadEntities` property of the configuration object (passed into the `forRoot()`
159+
method) to `true`, as shown below:
182160

183161
```ts
184162
@Module({
@@ -192,44 +170,42 @@ method) to `true`, as shown below:
192170
export class AppModule {}
193171
```
194172

195-
With that option specified, every entity registered through the `forFeature()`
196-
method will be automatically added to the entities array of the configuration
173+
With that option specified, every entity registered through the `forFeature()`
174+
method will be automatically added to the entities array of the configuration
197175
object.
198176

199-
> info **info** Note that entities that aren't registered through the `forFeature()` method, but
200-
> are only referenced from the entity (via a relationship), won't be included by
177+
> info **info** Note that entities that aren't registered through the `forFeature()` method, but
178+
> are only referenced from the entity (via a relationship), won't be included by
201179
> way of the `autoLoadEntities` setting.
202180
203-
> info **info** Using `autoLoadEntities` also has no effect on the MikroORM CLI - for that we
181+
> info **info** Using `autoLoadEntities` also has no effect on the MikroORM CLI - for that we
204182
> still need CLI config with the full list of entities. On the other hand, we can
205183
> use globs there, as the CLI won't go thru webpack.
206184
207185
#### Request scoped handlers in queues
208186

209-
> info **info** `@UseRequestContext()` decorator was added in v4.1.0
187+
> info **info** `@UseRequestContext()` decorator was added in v4.1.0
210188
211-
As mentioned in the [docs](https://mikro-orm.io/docs/identity-map), we need a clean state for each request. That is handled automatically thanks to the `RequestContext` helper registered via middleware.
189+
As mentioned in the [docs](https://mikro-orm.io/docs/identity-map), we need a clean state for each request. That is handled automatically thanks to the `RequestContext` helper registered via middleware.
212190

213191
But middlewares are executed only for regular HTTP request handles, what if we need
214-
a request scoped method outside of that? One example of that is queue handlers or
215-
scheduled tasks.
192+
a request scoped method outside of that? One example of that is queue handlers or
193+
scheduled tasks.
216194

217195
We can use the `@UseRequestContext()` decorator. It requires you to first inject the
218-
`MikroORM` instance to current context, it will be then used to create the context
219-
for you. Under the hood, the decorator will register new request context for your
220-
method and execute it inside the context.
196+
`MikroORM` instance to current context, it will be then used to create the context
197+
for you. Under the hood, the decorator will register new request context for your
198+
method and execute it inside the context.
221199

222200
```ts
223201
@Injectable()
224202
export class MyService {
225-
226-
constructor(private readonly orm: MikroORM) { }
203+
constructor(private readonly orm: MikroORM) {}
227204

228205
@UseRequestContext()
229206
async doSomething() {
230207
// this will be executed in a separate context
231208
}
232-
233209
}
234210
```
235211

@@ -281,4 +257,5 @@ export class PhotoModule {}
281257
```
282258

283259
#### Example
260+
284261
A real world example of NestJS with MikroORM can be found [here](https://github.com/mikro-orm/nestjs-realworld-example-app)

src/app/homepage/pages/microservices/custom-transport/custom-transport.component.html

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,38 @@ <h4 appAnchor id="client-proxy"><span>Client proxy</span></h4>
193193
connect
194194
event to dispatch: &#123; pattern: &#39;event&#39;, data: &#39;Hello world!&#39; &#125;
195195
</code></pre>
196+
<h4 appAnchor id="message-serialization"><span>Message serialization</span></h4>
197+
<p>If you need to add some custom logic around the serialization of responses on the client side, you can use a custom class that extends the <code>ClientProxy</code> class or one of its child classes. For modifying successful requests you can override the <code>serializeResponse</code> method, and for modifying any errors that go through this client you can override the <code>serializeError</code> method. To make use of this custom class, you can pass the class itself to the <code>ClientsModule.register()</code> method using the <code>customClass</code> property. Below is an example of a custom <code>ClientProxy</code> that serializes each error into an <code>RpcException</code>.</p>
198+
199+
<span class="filename">
200+
{{ 'error-handling.proxy' | extension: appb95b5d8490d1d2e5a8dfa4408547e4314e16a15a.isJsActive }}
201+
<app-tabs #appb95b5d8490d1d2e5a8dfa4408547e4314e16a15a></app-tabs>
202+
</span><pre><code class="language-typescript">
203+
import &#123; ClientTcp, RpcException &#125; from &#39;@nestjs/microservices&#39;;
204+
205+
class ErrorHandlingProxy extends ClientTCP &#123;
206+
serializeError(err: Error) &#123;
207+
return new RpcException(err);
208+
&#125;
209+
&#125;
210+
</code></pre><p>and then use it in the <code>ClientsModule</code> like so:</p>
211+
212+
<span class="filename">
213+
{{ 'app.module' | extension: appc6380cff174d3675b3c6660600efaf7aec5d9272.isJsActive }}
214+
<app-tabs #appc6380cff174d3675b3c6660600efaf7aec5d9272></app-tabs>
215+
</span><pre><code class="language-typescript">
216+
@Module(&#123;
217+
imports: [
218+
ClientsModule.register(&#123;
219+
name: &#39;CustomProxy&#39;,
220+
customClass: ErrorHandlingProxy,
221+
&#125;),
222+
]
223+
&#125;)
224+
export class AppModule
225+
</code></pre><blockquote class="
226+
info "><strong>hint</strong> This is the class itself being passed to <code>customClass</code>, not an instance of the class. Nest will create the instance under the hood for you, and will pass any options given to the <code>options</code> property to the new <code>ClientProxy</code>.
227+
</blockquote>
196228

197229
</div>
198230

0 commit comments

Comments
 (0)