Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Instance per request for mutation class

See original GitHub issue

Currently for mutations, a single instance of the mutations class (e.g. PeopleMutations) is created at startup. This differs ASP.NET Core controller classes, for which a new instance is created for each request. The instance-per-request approach allows dependency injection to be performed in the constructor, which is the preferred approach:

Prefer requesting dependencies as constructor parameters over resolving services from RequestServices. Requesting dependencies as constructor parameters yields classes that are easier to test.

Additionally, if several methods use the same DI parameters, the code for setting them up can be consolidated in the constructor, rather than having to be duplicated in each request method. EntityGraphQL mutations parallel controller methods and would benefit similarly, especially mutations that perform more than just database operations.

Relatedly, it’s worth noting that the DI conventions for controller methods and GraphQL mutations are currently reversed. For controller methods, DI services are annotated with FromServices and request data is not annotated. For GraphQL, DI services are not annotated and mutation arguments are annotated with MutationArguments.

It would increase consistency and reduce the learning curve of EntityGraphQL if mutations followed the conventions as MVC controllers for instance-per-request and DI. It would also open the door to not requiring a separate args class for each mutation and instead allowing mutation fields to be specified as parameters, since all parameters not marked with FromServices could be considered mutation fields.

Issue Analytics

  • State:closed
  • Created a year ago
  • Reactions:1
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

lukemurraycommented, Jun 11, 2022

Thanks for the feedback.

  1. Mutation class instance per request makes sense to support the common set ups in the constructor as you point out. Today you can have other setup methods in the class to help with that.
  2. Happy to add support for FromServicesAttribute however in ASP.NET 7 they are making that optional. I would seek to do the same and optionally support [FromServices]
  3. Totally agree with making the arguments on the mutation method the top level arguments in the GraphQL schema instead of the argument classes. Been on my mind for some time. [FromServices] is not required for this, just need to look up what are services and what isn’t

Thanks for the feedback, this is great.

lukemurraycommented, Jul 4, 2022

Hmm good point. I never thought of them as things like controllers until recently.

Previously they always had the lifetime of the schema which is generally a singleton. But could be what ever you register the schema as.

The new thing here is it now can inject services into the mutation constructor, which as you said if you register mutations as singletons and have services in the constructor then you hit the anti pattern.

Wasn’t an issue when you could only inject into the methods as that forced per request event though the object was not.

Good pickup. Makes sense to move towards always per request.

From: Edward Brey @.> Sent: Monday, July 4, 2022 11:14:06 PM To: EntityGraphQL/EntityGraphQL @.> Cc: Luke Murray @.>; State change @.> Subject: Re: [EntityGraphQL/EntityGraphQL] Instance per request for mutation class (Issue #126)

The 2.3.0 docs say:

When calling the mutuation it will ask the ServiceProvider for an instance of the class allowing for dependency injection at the constructor level, if that fails to return a result it will use Activator.CreateInstance.

Is that the right behavior? For ASP.NET Core controllers, I never thought of them as services themselves. For example, you don’t register them at startup. Instead, for each request, a controller instance is created and services are injected in. I would expect the same for the mutation objects (we can probably call them mutation controllers). They’d be created per request with ActivatorUtilities.CreateInstance, rather accessed as services.

As with MVC controllers, defining mutation objects as services can be an anti-pattern, depending on the lifetime. If the service is registered as a singleton, you’d no longer have instance-per-request and wouldn’t be able to inject per-request services into the constructor. You’d also have multiple threads running on the same object when processing concurrent requests.

— Reply to this email directly, view it on GitHub, or unsubscribe You are receiving this because you modified the open/close state.Message ID: @.***>

Read more comments on GitHub >

github_iconTop Results From Across the Web

Python: Instance class mutation
So, in my code I have an Egg instance. When it's time I would like transform them into Larvae instances. I can create...
Read more >
Mutations in Apollo Kotlin
Similar to queries, mutations are represented by instances of generated classes, conforming to the Mutation interface. Constructor arguments are used to ...
Read more >
Mutations in Apollo Client
If your mutation returns all of the objects and fields that it modified, you can update your cache directly without making any followup...
Read more >
Mutations - Hot Chocolate
With multiple mutations executed serially in one request it can be useful to wrap these in a transaction that we can control.
Read more >
Mastering Mutations in React Query | TkDodo's blog
Mutations are, per design, not directly coupled to queries. A mutation that likes a blog post has no ties towards the query that...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Post

No results found

github_iconTop Related Hashnode Post

No results found