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

(Question) Is it possible to set LocalContext for child resolvers? #161

Open
abishai opened this issue Sep 12, 2021 · 7 comments
Open

(Question) Is it possible to set LocalContext for child resolvers? #161

abishai opened this issue Sep 12, 2021 · 7 comments

Comments

@abishai
Copy link

abishai commented Sep 12, 2021

Hello, I'm playing with KGraphQL library to see if I can port my pure GraphQL controller to it, however I've found no way how to set LocalContext. I use it extensively to provide common state from root resolver to child resolvers. I've found Context class with map, however it has no set method.

I'm speaking about this feature of GraphQL: https://github.com/graphql-java/graphql-java/blob/master/src/main/java/graphql/execution/DataFetcherResult.java#L81

So, I can write

        val result = DataFetcherResult.newResult<>()
        val data = ......
        result.localContext(......)
        return result.data(data).build()

Can I do the same thing in KGraphQL ?

@abishai abishai changed the title Is it possible to set LocalContext for child resolvers? (Question) Is it possible to set LocalContext for child resolvers? Sep 12, 2021
@abishai
Copy link
Author

abishai commented Sep 12, 2021

I've written the following extension functions, I am not happy with solution, but it works. Maybe you can provide some official way to do similar thing? I can't make resolvers self-sufficient everywhere as I need a shared state for some of them.

    @Suppress("UNCHECKED_CAST")
    fun Context.set(key: Any, value: Any) {
        val field = Context::class.java.getDeclaredField("map")
        val map = field.also { it.isAccessible = true }.get(this) as MutableMap<Any, Any>
        map[key] = value
    }

    @Suppress("UNCHECKED_CAST")
    fun <T> Context.get(key: Any): T {
        val field = Context::class.java.getDeclaredField("map")
        val map = field.also { it.isAccessible = true }.get(this) as MutableMap<Any, Any>
        return requireNotNull(map[key]) as T
    }

@jeggy
Copy link
Member

jeggy commented Sep 13, 2021

Currently this is not something that is supported. A feature request for it is mentioned here #129 and will most likely be included in some future versions of KGraphQL.

How I'm solving this is I have a all data needed directly on the type returned from the resolver and if some of the fields should not be available within GraphQL I would use the ignore functionality.

@abishai
Copy link
Author

abishai commented Sep 13, 2021

I see, but this way is not optimal for some cases. Well, I'll have to use my hack until proper solution is implemented. Can you just provide setters for Context map? Seems easy and trivial. I can make a PR if you wish :)

@jeggy
Copy link
Member

jeggy commented Sep 13, 2021

PRs are always welcome 👍

I would guess you want this because you want to pass data from the grandparent nodes or something like this to your resolver and this pattern is not recommended when designing a GraphQL schema. Instead every resolver should always live on it's own.
But that being said, I think we would like to offer developers to work how ever they want, so if you could provide a PR for #129, then that would be great.

@jeggy
Copy link
Member

jeggy commented Sep 13, 2021

And just to be sure you are not reporting this in the wrong repository. All code and links you provided are for the graphql-java implementation of GraphQL.

KGraphQL and graphql-kotlin/graphql-java are not related.

@abishai
Copy link
Author

abishai commented Sep 13, 2021

Well, I'm writing options trading software (for personal use) and I have a user case where I compute my position stats, that in case of options can be rather complex. Every option has underlying asset, that is the same for several options in position; underlying asset has it's own market data, so if I want coherent calculus, I must cache (at least) market data of underlying asset. As math can be complex (fetches data from different microservices, uses iterative algorithms, ....) I'd like to avoid computation of entire object every time and provide only requested data. That's the cardinal idea of graphql, to provide only that is asked. :p So, probably, I'll stick with not recommended way and make a PR..

@jeggy
Copy link
Member

jeggy commented Sep 13, 2021

Adding support for adding custom data to the GraphQL Context will only help you a little bit as the Context only lives per request.
Why not have some cache living on the side like caffeine.

How I normally solve this issue is to have cache saved using Caffeine alongside a RabbitMQ cluster to invalidate the cache when needed. This way I always have up to date cache ready for use across all GraphQL requests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants