-
Notifications
You must be signed in to change notification settings - Fork 312
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
Cannot inject DataLoader<> directly from auto configured @BatchMapping #1023
Comments
@xcq1 what version are you upgrading from, or is this from a different framework altogether? In other words, is it a specific feature in 1.3 or just generally converting to Spring for GraphQL. At any rate, we should start by making it clear that use of As for how the injected Also keep in mind we have pagination support as of version 1.2 that may be relevant to you. |
@rstoyanchev Thanks for the pointers. I'm upgrading from graphql-java-kickstart with a lot of custom code that deals with handling federation, data loaders, etc. Definitely will take another look at the support for pagination, nullability and Querydsl. So I got further by following your suggestion to create a BatchLoader with a top-level query something like this, and then also the DataLoader can be injected directly: @Controller
class TriangleController(registry: BatchLoaderRegistry, ...) {
init {
registry.forTypePair(TriangleId::class.java, TriangleGraphQL::class.java).registerMappedBatchLoader { keys, _ ->
Mono.just(
triangleRepository.getAllFromIds(keys).toMap()
)
}
@QueryMapping
fun triangles(@Argument id: TriangleId, dataLoader: DataLoader<TriangleId, TriangleGraphQL>): CompletableFuture<TriangleGraphQL> {
return dataLoader.load(id)
}
} But now oddly enough, when I want to use the same for a federated query the same approach does not work: @EntityMapping
fun triangle(
@Argument idList: List<String>,
dataLoader: DataLoader<TriangleId, TriangleGraphQL>
) : CompletableFuture<List<TriangleGraphQL>>? {
// formatArgumentError: Could not resolve parameter [1] in public java.util.concurrent.CompletableFuture<java.util.List<....): No suitable resolver
return dataLoader.loadMany(idList.map { TriangleId(it) })
} This means I need to do this again which seems strange since it requires again knowledge about with which name it got registered in the first place: val dataLoader = dataFetchingEnvironment.getDataLoader<TriangleId, TriangleGraphQL>(TriangleGraphQL::class.java.name) Am I misunderstanding something there as well? I think part of my confusion also stems from the association that all things essentially just map ids to objects, so "retrieving an object by id" should be no different whether I want that object to respond to a query, to a federated entities call or to resolving a field from a different object. Shouldn't it be possible to define it one time and then have some customizable "boiler plate" generated automatically? |
You cannot use the DataLoader mechanism on top level methods like |
Please forgive my ignorance, but is there a specific reason why this should not be done on |
The DataLoader mechanism is for nested fields where the N+1 problem arises. There is no need for that at the top where you can return a list. Just a like you return a List for a query that returns multiple items. This was also discussed previously at #922 (comment). |
Thanks for the explanation. I understand your point, but I wanted to give two more inputs here:
|
Aside from re-using your existing code, I'm curious, in relation to data loader caching, do you actually have cases where a federated type appears again in nested parts of the graph, and is that even supported in federation? |
@xcq1 coming back to this, as the original description started from a different question, I've created a new issue #1095, and plan to experiment. It occurs to me that support for |
I'm in the process of porting an existing project to spring-graphql 1.3.1 and want to use all of its convenience features for more readable code. From the docs about annotated controllers I gathered that defining and reusing DataLoaders should be quite easy. I have a setup similar to this:
But when I try to query this, I run into an exception:
I was trying to change some internal names to get it to work out of the box, but upon debugging a bit I am confused how this is supposed to work:
<typeName>.<fieldName>
. Both are overridable from the annotation, typeName is by defaultClass<>.getSimpleName()
:https://github.com/spring-projects/spring-graphql/blob/v1.3.1/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java#L324
Class<>.getName()
(fully-qualified) OR alternatively<parameterName>
a few lines after:https://github.com/spring-projects/spring-graphql/blob/v1.3.1/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataLoaderMethodArgumentResolver.java#L57
Not only will the class names never match by default, because one is simpleName and one is package-qualified, but it is impossible to select an existing data loader since a.) I cannot configure the
@BatchMapping
annotation to not include a dot and b.) I cannot request injection of a data loader with dot in the name since dots are (thankfully) illegal in parameter names.Am I missing something and there is a reason for this? To me it sounds as if the DataLoaderMethodArgumentResolver should actually request the same kind of pattern of
<simpleClassName>.<parameterName>
by default.So to get this to work currently I have to inject the environment and find it by knowing the naming convention of AnnotatedControllerConfigurer:
The text was updated successfully, but these errors were encountered: