Closed woltob closed 3 years ago
Can't help much with GQL, never really used it myself, but I can see how this combinations is popular - would be indeed great to have such example app, more complete one similar to the realworld example app.
Regarding AsyncLocalStorage
, it is already used by default in v5 with the RequestContext
helper. I don't plan to add more guides for v4, if something, will target v5.
Would be probably best to adjust some existing example project and just swap the ORMs (and adjust the ORM specific parts). Do you know of something usable? Otherwise I don't have a clue, most of the points you mentioned are something I never used myself, so can't provide best practices 🤷.
Will pin this for some time, maybe someone can help.
After a long love-hate relation with TypeORM I'm now checking out MikroORM. I usually work with NestJS, GraphQL and TypeGraphQL (code-first approach), so I'll give that a try. I'm not aware of any specific example using these libraries, but I'll give it a go to create RealWorld like app (is there a GQL spec for this?) based on my experience. Together we should be able to figure this out :+1: I'm personally interested in adding dataloaders scoped to a single request, so I'll try that too.
I'll post here when I have something to show.
@briandiephuis are you using Postgres as the database?
@woltob Yes, I refactored the example to Postgres :muscle:
I also decided to put the authentication (sign in, sign out, refresh token and forced sign-out) outside of GraphQL. This has worked well for me in the past and seems to be best practice for token based auth. This allows us to use a http-only refresh cookie on the /auth
route. Token based auth through GQL would make it so that the refresh cookies would have to be sent on every request which doubles the size of auth-related stuff on each request. I'm interested in what you all think about this :) (More details in the readme)
It's a bit more work than expected, and far from finished, but I'm getting somewhere now. See: https://github.com/briandiephuis/nestjs-realworld-example-app
I found an example of using Mikro-ORM with TypeGraphQL here: https://github.com/MichalLytek/type-graphql/tree/master/examples/mikro-orm but it is built on a bare ApolloServer. There they fork/clone the identity manager for each request here. I found this in the docs:
app.use((req, res, next) => {
RequestContext.create(orm.em, next);
});
@B4nan How can we get access to the orm
object to clone the EntityManager when using NestJS? I think I should add it to each gql request here
To elaborate on the problem; currently lazy loaded relations do not work:
The user.entity
has this relation;
@Field(() => [Article])
@OneToMany(() => Article, (article) => article.author)
articles = new Collection<Article>(this);
Pretty much exactly as shown here: https://github.com/MichalLytek/type-graphql/blob/master/examples/mikro-orm/entities/recipe.ts#L22
I'm planning of implementing dataloaders, and using lazy-loaded relations is usually a bad practise - but they are super useful for fast prototyping. Plus, dataloaders also require a request scoped entity manager.
Be sure to read this: https://github.com/mikro-orm/nestjs/issues/22
Also as I already said, I really can't help much with GQL, so if you want help, please try to narrow it down to something that is not GQL related.
Also worth reading: https://jenyus.web.app/blog/2021-03-07-nestjs-starter
Also having troubles with getting orm object for get clear identity map on each request.
Like the docs says, we should use middleware:
app.use((req, res, next) => {
RequestContext.create(orm.em, next);
});
It's not a GQL problem, with Nest we have injected MikroORM Module and I don't understand how I can get orm
object outside to use it in middleware. @B4nan can you explain please?
Hm.. maybe I found the solution
@briandiephuis try this:
import { MikroORM } from '@mikro-orm/core';
import { AppModule } from './app.module';
import { storage } from './storage';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const orm = app.get(MikroORM);
app.use((req, res, next) => {
storage.run(orm.em.fork(true, true), next);
});
// or without AsyncLocalStorage
app.use((req, res, next) => {
RequestContext.create(orm.em, next);
});
}
Thanks for the tip @notmedia . That seems to work, and I've also found a more NestJS way by formatting your solution as NestJS middleware.
@Injectable()
export class MikroOrmRequestContextMiddleware implements NestMiddleware {
constructor(private readonly orm: MikroORM) {}
use(req: AppRequest, res: Response, next: NextFunction): void {
RequestContext.create(this.orm.em, next);
}
}
Now both dataloaded relations and more naively loaded relations work. Without pagination, though. That'll be a whole other story.
Getting auto-loaded relations to work seems to be impossible. But like I said, it's basically only useful for quick prototyping so I'm not too sad about that.
I'm swamped with work but I'll try to finish this example app :smile:
Yeah, this approach is better
has anyone got a per-request Identity Map working when using nestJs + graphql with the fastify adapter?
@rathax have you tried our approaches we posted above? If there is a bug, could you please post it here?
@notmedia
yes, that's why I have asked if anyone got it working with fastify or if I just have missed something.
@rathax I can't help you without any information
We've got a commercial project that has NestJS set up with MikroORM / GraphQL with extensive support for authn/z, caching, cursor/offset pagination, extremely flexible query conditions, etc... I can't share the code, but I can talk about bits of it if anyone has questions.
e.g.: we don't use a dataloader, instead we break down the GraphQL query to determine which relations need loading and populate that all-at-once, instead - basically a heavily modified version of this: https://github.com/driescroons/graphql-fields-to-relations
e.g.: we don't use a dataloader, instead we break down the GraphQL query to determine which relations need loading and populate that all-at-once, instead - basically a heavily modified version of this: driescroons/graphql-fields-to-relations
What about contributing back to that library, or releasing your own version? :] Or an article about how you do things. I am quite sure all of that would be quite welcome.
Hi @jamesmeneghello ,
that sounds amazing. Perhaps you can publish a stripped down version of your code and setup (especially the configuration). I, and I guess many others, would be very interested in comparing and discussing solutions. Also, a Medium article with code bits and pieces would be much appreciated.
Such a barebone boilerplate project would be an amazing starting point for others to venture out and build something amazing.
Let us know, thanks!
Let me have a think about the best way to disseminate it - it'll probably take a couple of weeks to write up anyway, and it's pretty opinionated, but it has some fairly cool stuff in it.
@jamesmeneghello Would love to have a talk about this! I'd love to elaborate on the repo, especially when we're getting closer to v5.
Hi B4nan,
you're doing amazing work with Mikro ORM and I can see this rising to become the standard ORM for NodeJS w/ Typescript, especially with NestJS.
Since GraphQL APIs are becoming more and more common for new projects where front-ends would be tightly coupled with their respective back-end APIs, I was wondering whether you (with the help of some NestJS and Apollo experts), could provide an example app with a go to configuration and setup, especially with regards to a clean per-request Identity Map via the Async Storage of the newer Node frameworks.
Required features:
I think this would be a good setup and base for many more project to start from.
Keep up the amazing work!