I want to implement pagination into custom type fields using arguments.
Using a sample schema like this:
type Book {
title: String!
year: Int!
}
type Author {
name: String!
books(page: Int, size: Int, sort: String): [Book!]!
}
type Query {
allAuthors: [Author!]!
}
How do I implement the query for books(page: Int, size: Int, sort: String): [Book!]!
with Spring GraphQL? I know that the queries for the type Query
are implemented in a @Controller
annotated class with @SchemaMapping
annotated methods, but that does not seem to work for my data transfer AuthorDto
class.
The application does not throw an exception or a warning when starting up or during runtime, but using the query just gives me a generic error telling me it is not implemented.
{
"errors": [
{
"message": "The field at path '/allAuthors[0]/books' was declared as a non null type, but the code involved in retrieving data has wrongly returned a null value. The graphql specification requires that the parent field be set to null, or if that is non nullable that it bubble up null to its parent and so on. The non-nullable type is '[Book!]' within parent type 'Author'",
"path": [
"allAuthors",
0,
"books"
],
"extensions": {
"classification": "NullValueInNonNullableField"
}
}
],
"data": null
}
I've tried using the @SchemaMapping
in the data transfer object like this:
data class AuthorDto(
private val author: Author // author is the actual Author model class
) {
val name: Int
get(): author.name
@SchemaMapping(typeName = "Author", field = "books")
fun getBooks(
@Argument page: Int? = null,
@Argument size: Int? = null,
@Argument sort: String? = null,
): List<Book> {
// my implementation for creating the list with pagination
}
}
However, Spring does not seem to pick up the implementation. Because this class uses my data model Author
class in the constructor (like in the sample https://github.com/spring-projects/spring-graphql/blob/1.0.x/samples/webmvc-http/src/main/java/io/spring/sample/graphql/project/Project.java), I cannot annotate it with @Controller
and doing that also wouldn't make any sense to me in the first place.
I'm using Kotlin, but I would appreciate solutions on how to accomplish that in Java.
To implement the query allAuthors
with Spring for GraphQL you should have the following method in your @Controller
-annotated class:
@Controller
public class MyGraphqlController {
@QueryMapping
List<AuthorDto> allAuthors(){
// implementation for creating the list with pagination
}
}
Mind a couple of things:
The AuthorDto
class (data class, Java record, etc) should have the same fields as the ones defined in your schema.graphqls
, which seems to not be the case at the moment.
In your schema.graphqls
definition, I see the Author
has an array of Book
, which is OK, but this field has arguments
books(page: Int, size: Int, sort: String): [Book!]!
I'm not sure this is allowed inside a custom type definition in GraphQL (type Book{...}
), which is not a query, mutation or subscription.
EDIT
Regarding the books
inside the Author
, I have never used @Argument
inside a @SchemaMapping
other than a Query
or a Mutation
. I would try this under your @QueryMapping
:
@SchemaMapping
List<Book> books(Author author, @Argument Integer page, @Argument Integer size, @Argument String sort){
// your logic
}