Reputation: 4694
I am using graphql-java with graphql-java-annotations in my Spring application (spring-graphql-common seemed very limited and looks like it's not maintained anymore), and I'm struggling with subfields manipulation.
I have two classes A
and B
that I want to access using GraphQL, here they are:
class A {
@GraphQLField
Integer id;
@GraphQLField
String name;
@GraphQLField
List<B> listOfB;
}
class B {
@GraphQLField
Integer id;
@GraphQLField
String code;
}
I can successfully query all the fields in A
and also the fields in B
using the following schema:
@Component
public class Schema
{
public GraphQLObjectType aType;
public GraphQLSchema aSchema;
public GraphQLObjectType queryType;
@Autowired
public Schema(DataFetcher dataFetcher) throws IllegalAccessException, InstantiationException, NoSuchMethodException
{
aType = GraphQLAnnotations.object(A.class);
queryType =
GraphQLObjectType
.newObject()
.name("QueryType")
.field(GraphQLFieldDefinition.newFieldDefinition()
.name("a")
.type(aType)
.argument(GraphQLArgument.newArgument()
.name("id")
.type(new GraphQLNonNull(Scalars.GraphQLInt))
.build())
.dataFetcher(dataFetcher)
.build())
.build();
aSchema = GraphQLSchema.newSchema()
.query(queryType)
.build();
}
}
I can successfully filter on a
with the following request:
{
a(id:5)
{
id,
name,
listOfB
{
code
}
}
}
But when I try to filter on listOfB
, for example with a take
to select only X records, I have the error Validation error of type UnknownArgument: Unknown argument take
:
{
a(id:5)
{
id,
name,
listOfB(take:3)
{
code
}
}
}
I understand what the error means, as I haven't declared any possible argument for the listOfB
field on A
, but I don't know how I could possibly do it using graphql-java-annotations
.
I have added a specific DataFetcher
for listOfB
tho, using the following code in class A
:
@GraphQLDataFetcher(BDataFetcher.class)
private List<B> listOfB;
and it is indeed getting called when I retrieve listOfB
.
Do you have any idea on how I could add arguments to fields when using graphql-java-annotations
? If not, is there any workaround?
Defining the schema without annotations and using the "classic" way of graphql-java
is not an option as my schema is really huge :/
Thanks :)
Upvotes: 2
Views: 7033
Reputation: 952
I highly recommend you to look again at this library, as it is now back to be maintained, and the readme is very clear.
As for you question:
You should make you field listOfB
like this:
@GraphQLField
@GraphQLDataFetcher(ListOfBFetcher.class)
List<B> listOfB(int take){return null};
and in the dataFetcher you can get the take
argument from the environment
variable (via enviroment.getArgument("take")
)
You can also make the method the dataFetcher itself by doing:
@GraphQLField
List<B> listOfB(int take, DataFetchingEnvironment environment){
//return the list of B
};
Upvotes: 1
Reputation: 4694
It is not the solution I ended up using because it doesn't fit my design, but here's what you can do:
public class MyClass
{
@GraphQLField
private Integer id;
private List<String> items;
@GraphQLField
public List<String> items(DataFetchingEnvironment environment, @GraphQLName("take") Integer take, @GraphQLName("after") Integer after)
{
List<String> items = ((MyClass) environment.getSource()).getItems();
Integer fromIndex = 0;
Integer toIndex = items.size();
if (after != null)
fromIndex = after + 1;
if (take != null)
toIndex = fromIndex + take;
return items.subList(fromIndex, toIndex);
}
}
It sucks because you're not using a DataFetcher
so your code will be copy/pasted everywhere, but it still works.
But I found a way to use a DataFetcher
, that said it's weird and I guess it's not a proper use of the library, but who knows:
public class MyClass
{
@GraphQLField
private Integer id;
private List<String> items;
@GraphQLField
@GraphQLDataFetcher(MyClassDataFetcher.class)
public List<String> items(DataFetchingEnvironment environment, @GraphQLName("take") Integer take, @GraphQLName("after") Integer after)
{
return null;
}
}
This will make the arguments take
and after
is the DataFetchingEnvironment
in your MyClassDataFetcher.get()
method, so you have an empty method that is not getting called but the arguments are still passed to your DataFetcher
.
Again, it's not ideal because I doubt it's how it's meant to be used, but it's the only way of using a DataFetcher
with arguments that I'm aware of.
Now, I didn't use any of those two solutions and I ended up dropping completely graphql-annotations
and developed my own solution with custom annotations that are allowing me to automatically build the schema (won't be released publicly, sorry).
I wouldn't recommend using graphql-annotations
until they have proper documentation for all the use cases.
Upvotes: 1