Alternative NestJS Approach
See original GitHub issueIn moving to a persist/flush model system like Mikro, I find it important to prevent developers on my team from making mistakes like using some global entity manager with a persisted identity map across requests. At the moment, it is very easy to inject Mikro into any service, controller, etc without realizing the repercussions. At a high level, these are my requirements:
- No one should be able access a singleton instance of EntityManager except for the Mikro module itself.
- If there is ever a need to access the application-level singleton, it should be done through some obvious abstraction like
orm.getGlobalEntityManager()
- No magic should be involved with request scopes such as node.js domains (deprecated) or pulling things from global statics. Given that a service does not know if it needs to be ran in a transaction or not, guidance/best practice should be to always pass an instance of
EntityManager
to your downstream services via function arguments - The Mikro NestJS module should provide interceptors and decorators for making request scoped work easier (i’m using this for both REST and GraphQL endpoints), example:
EntityManagerInterceptor.ts
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { EntityManager } from '@mikro-orm/postgresql';
import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';
import { Observable } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
export default class EntityManagerInterceptor implements NestInterceptor {
constructor(private em: EntityManager) {}
async intercept(context: ExecutionContext, next: CallHandler<any>): Promise<Observable<any>> {
context['em'] = this.em.fork();
return next.handle().pipe(
mergeMap(async (output) => {
await context['em'].flush();
return output;
})
);
}
}
RequestEntityManager.ts
export default createParamDecorator((data: unknown, context: ExecutionContext) => {
if (!context['em']) {
throw new Error('Could not find a request-scoped EntityManager');
}
return context['em'];
});
// graphql
@Mutation()
myMutation(@RequestEntityManager() em: EntityManager){}
// rest
@Get()
async myEndpoint(@RequestEntityManager() em: EntityManager){}
Issue Analytics
- State:
- Created 2 years ago
- Reactions:2
- Comments:6 (3 by maintainers)
Top Results From Across the Web
List of NestJS Alternative and features - eduCBA
1. Ext Js. Ext Js is the best alternative for NestJS. It is pure JavaScript application framework used to build the cross-web application...
Read more >What are some real alternatives to NestJS? : r/node - Reddit
I'm not a fun of NestJS (and of frameworks in general), but I'd like to understand more about your statements about OOP and...
Read more >Comparing 4 popular NestJS ORMs - LogRocket Blog
Make choosing your NestJS ORM easy with this detailed guide to four of the most popular options: Sequelize, TypeORM, MikroORM, and Prisma.
Read more >Why I choose NestJS over other Node JS frameworks - Medium
I am a big fan of NodeJS for its thin simplistic approach. I have been using Node.js since 2011–12 and Express has been...
Read more >Next.JS vs Nest.JS – What to choose for your next project?
Cons of Nest.js · Nest is a well-built software application with top-notch features and integrations. · Although Nest holds an edge in their ......
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Just tossing this here in case anyone finds it useful. I am using it for
@nestjs/microservices
since Middleware doesn’t run in this context.It of course has the limitation (being at the interceptor level) of not affecting guards, but for my use case I actually don’t need that as all my guards are at the gateway level which issue request to other services which would do their business logic past any interceptors.
A note on a PR I may look into introducing, the
RequestContext.createAsync()
usesasync
so it can only handle promises, but theAsyncLocalStorage.prototype.run()
can handle any type of returned value, so I am thinking of introducing aRequestContext.bind()
or something like that which just callsthis.storage.run()
without theasync
and promises.I mean you can’t flush in parallel (for that you need forks with their own UoW instance), for reading it should be fine.