Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to use Context? #1138

Open
Sam-Kruglov opened this issue Feb 27, 2025 · 3 comments
Open

How to use Context? #1138

Sam-Kruglov opened this issue Feb 27, 2025 · 3 comments
Labels
status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged

Comments

@Sam-Kruglov
Copy link

Confused on the documentation. So, the docs talk about using io.micrometer.context.ThreadLocalAccessor but doesn't give any full examples, e.g. I don't understand what you mean by "register it manually on startup or by calling io.micrometer.context.ContextRegistry#getInstance()" - you mean server startup like in on context refresh or do you mean like on request startup, so I have to add some sort of interceptor to deal with it? There's a quick mention of @LocalContextValue as well as GraphQLContext that it can be injected into the method signature - that seems like what I actually need, not sure why even mention micrometer stuff?

My usecase is that I want to return a partial result: I paginate through items, at some point the items might become bad so I will include both the items and corresponding errors/extensions. If I throw an error, data is null, so I return normally but set context and then in an interceptor I check it and populate the errors/extensions.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Feb 27, 2025
@Sam-Kruglov
Copy link
Author

Current solution:
In the resolver I inject context: GraphQLContext, then I use context.put("stuff", stuff) during resolver, then inside of WebGraphQlInterceptor I can get it from response.executionInput.graphQLContext and edit final response via response.transform where I can add errors alongside data.

@bclozel
Copy link
Member

bclozel commented Feb 28, 2025

I think you're conflating two different concepts: context propagation and the GraphQL context.

Context propagation in Spring for GraphQL and the Context Propagation Library are about propagating context values from one context object to another: thread locals, the GraphQL Context, the Reactor Context. While traditional, "one thread per request", applications use thread locals for such things, this doesn't work as soon as you're opting in for a different execution model. Context propagation helps you to seamlessly use all of those together.
Registering a ThreadLocalAccessor needs to happen as early as possible with the static API or using the ServiceLoader mechanism (see an example here).

The GraphQL Context is a map that applications can use to store any relevant information for fetching data: security authorities, hints, etc.

It seems your problem is mostly related to partial data and nullability in the schema? Maybe you can share a small code snippet showing that part of your schema and the relevant @SchemaMapping methods?

@bclozel bclozel added the status: waiting-for-feedback We need additional information before we can continue label Feb 28, 2025
@Sam-Kruglov
Copy link
Author

Sam-Kruglov commented Feb 28, 2025

So ThreadLocalAccessor needs to register once on app startup, not once per request? I want to store some stuff in the request-only context, so the next request should not have any data I added.

I want to populate graphql context (or whatever context, I don't mind if I use an abstraction, maybe it's better for consistency) with errors so that right before returning data I can also populate errors in the response alongside it.

I found a good example that's very similar to what I want: https://stackoverflow.com/questions/71795252

I have a paginated endpoint (Connection) and as I generate new items I want to include errors/warnings saying that the list that is getting generated is going off the tracks but I still want to return the items to draw a graph in my UI. So the UI will show the graph and it will also show warnings/errors about it. Let me know if you still want the exact code, it'll take me some time to anonymize it...

My current solution (described in the last comment) works fine, I just declare a @QueryMapping method parameter GraphQLContext and then forward it around in all internal methods and eventually might call GraphQLContext#put in case there's something wrong with the data but I still want to show the data. Then outside of the resolver, in an interceptor, I populate the errors by checking out the context. To be more specific, I only store a single key in GraphQLContext under the name my-xx-errors - and that is a list of elements of MyErrorObject type. Every time I find some sort of issue with my data, I add an item in that list. And the interceptor then maps each MyErrorObject into a GraphqlError.

I don't like that I must forward GraphQLContext everywhere and pollute my method signatures with it, thread local would be nice, I wish I could just call some static method to populate the context instead. I tried debugging ContextRegistry#getInstance().get*() methods but couldn't find anything that would get me access to GraphQLContext. Let me know if you have an idea for that. I am using servlet stack for now.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Feb 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged
Projects
None yet
Development

No branches or pull requests

3 participants