AntoineB AntoineB - 10 days ago 5
Java Question

GraphQL + Java - How do I filter subfields?

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 :)

Answer

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(MyClass.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.

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 I found.

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.

Comments