Indexing List Type field in a GraphQL type from within a Query - graphql

Say I have the following GraphQL Schema
query {
allAuthors: [Author]
}
type Author {
id: ID!
name: String!
books: [Book]
}
type Book {
id: ID!
name: String!
author: Author!
}
Now I can successfully run the following query to get all the authors and their associated books
query {
allAuthors {
name,
books {
name
}
}
}
However, if I only want to get the first three books for all authors, how would I go about doing something like that? Can we index the books field in the Author type from within a query? If so, how?
I tried something like this and it doesn't work
query {
allAuthors {
name,
books[3] {
name
}
}
}

GraphQL doesn't have syntax for this.
You can add a "limit" parameter to a field, and this is common enough:
type Query {
allAuthors(limit: Int, offset: Int): [Author!]!
}
type Author {
id: ID!
name: String!
books(limit: Int, offset: Int): [Book!]!
}
If you add parameters like this to the schema, then the query you want (for all authors, get the first three books) could look like
{
allAuthors {
name
books(limit: 3) {
name
}
}
}

Related

Spring GraphQLmultiple schemas with Query per file

with Spring-GraphQl if I have following two schemas in the resources/graphql folder:
schema1:
type Query {
bookById(id: ID): Book
}
type Book {
id: ID
name: String
pageCount: Int
author: Author
}
type Author {
id: ID
firstName: String
lastName: String
}
schema2:
type Query {
personByName(name: String): Person
}
type Person {
id: ID
firstName: String
lastName: String
}
Spring-GraphQL seems to be merging them into one GraphQL schema file and starting of Spring-Boot Graphql app ends with following error:
Caused by: graphql.schema.idl.errors.SchemaProblem: errors=['Query' type [#1:1] tried to redefine existing 'Query' type [#1:1]]
When I change it to:
schema1:
type Query {
bookById(id: ID): Book
personByName(name: String): Person
}
schema2:
type Book {
id: ID
name: String
pageCount: Int
author: Author
}
type Author {
id: ID
firstName: String
lastName: String
}
type Person {
id: ID
firstName: String
lastName: String
}
it works perfectly good and I am able to call both queries with graphiql. How graphql spring works with multiple schemas? It seems spring-graphql merges files into one schema so multiple Query types per file breaks the app.
Thanks for answer.
Spring GraphQL is loading all schema resources under the configured location and is using TypeDefinitionRegistry::merge to create a single schema out of them.
I think that redifining any type (even the Query one) should raise an error, otherwise this could hide important issues and conflicting schema definitions. That's what GraphQL Java's TypeDefinitionRegistry is doing.
You can organize your schema files like this:
graphql/schema.graphqls
type Query {
}
// add common directives, scalars, etc
graphql/books.graphqls
extend type Query {
bookById(id: ID): Book
}
type Book {
id: ID
name: String
pageCount: Int
author: Author
}
type Author {
id: ID
firstName: String
lastName: String
}
graphql/person.graphqls
extend type Query {
personByName(name: String): Person
}
type Person {
id: ID
firstName: String
lastName: String
}

Graphql: User Error: expected iterable, but did not find one for field XXX

This is movie schema:
type Book {
id: ID!
title: String
author: [Author] #belongsTo(relation: "author")
}
This is how I related book and author
public function author()
{
return $this->belongsTo('App\Models\Author', 'id', 'book_id');
}
This is schema for author
type Author {
id: ID!
title: String!
book_id: Int!
}
This is my query for Book:
extend type Query {
bookCriteria(
orderBy: _ #orderBy
where: _ #whereConditions
): [Book!]! #paginate
}
This is how I query:
{
bookCriteria
(
first: 1, page: 1
)
{
data
{
id
uuid
author
{
id
title
}
}
}
}
Finally, this is what I get as error message:
"User Error: expected iterable, but did not find one for field Book.author."
If I use hasMany instead of belongsTo, it works fine.
Please let me know what is wrong here?
Your type should be
type Book {
id: ID!
title: String
author: Author #belongsTo(relation: "author")
}

GraphQL query with multiple nested resolvers and mapping fields to arguments

From GraphQL Client's perspective, how do I perform a query with multiple nested resolvers where the fields from the parent are passed as arguments to the child resolver?
Here is a minimal example:
GraphQL Schema:
type Author {
id: ID!
name: String!
}
type Book {
id: ID!
title: String!
releaseDate: String!
}
type Query {
// Returns a list of Authors ordered by name, 'first' indicates how many entries to return
getAllAuthors(first: Int!): [Author]!
// Returns a list of Books ordered by releaseDate, 'first' indicates how many entries to return
getBooksByAuthorId(first: Int! authorId: ID!): [Book]!
}
Is it possible to write a query to get all authors and their last released book? Something around the lines:
query GetAuthorsWithLastBook($first: Int!) {
getAllAuthors(first: $first) {
authorId: id
name
lastBook: getBooksByAuthor(1, authorId) {
title
}
}
}
In the example above, I attempted to alias getAllAuthors.id as authorId and pass the alias down as argument to getBooksByAuthor(...) but that didn't work.
The key aspect of the problem is that I don't know the authorIds beforehand. I could fetch the authors first and build a query to fetch their last book but that will result in multiple queries and that is something I would like to avoid.
Update
A Java Kickstarter example is available here: https://www.graphql-java-kickstart.com/tools/schema-definition/
yes, on the graphql definition, you need to add lastBook in the Author
type Author {
id: ID!
name: String!
lastBook: [Book]
}
Next up u need to write the resolver for the lastBook
const resolvers = {
Query: {
Author {
lastBook: (parent, args) {
const userId = parent.id;
return getBooksByAuthor(userId, 1);
},
}
}
};

Prisma append custom field to info argument when querying data

I am trying to append extra fields to the info object when querying data from prisma database. I have seen this post but I can't get fragments working.
I have below migrations:
type User {
id: ID! #unique
name: String
}
type Video {
id: ID! #unique
name: String
likes: [Like]
}
type Like {
id: ID! #unique
user: User
createdAt: DateTime!
}
Now, I would like to query all videos and check if current user has already liked a video. If so, the likes object should read the createdAt value, otherwise it would be empty.
I am doing this in playground via following query:
query {
videos() {
id
name
hasVoted: likes(where: {user: {id: "cjr7r85jy00rc0892dfwpu96u"}){
createdAt
}
}
}
this works but I would like to add the hasVoted to my query resolver to automatically append it to all queries. How can I do this ?
I tried solving it via fragments but without luck:
videos: {
fragment: `fragment hasVoted on Video {
hasVoted: likes (where: {user: {id: "cjr7r85jy00rc0892dfwpu96u"}}){
createdAt
}
}`,
resolve: async (_, args, ctx, info) => {
return await ctx.prisma.query.videos({},info);
}
}
Anyone has some ideas how I can do this? thx!
You can use addFragmentToInfo from graphql-bindings
https://oss.prisma.io/content/graphql-binding/02-api-reference#addfragmenttoinfo

Entity Association syntax issue with graphql queries

I am trying to understand graphql's query and mutation syntax. Given this example:
type Author {
id: Int!
firstName: String
lastName: String
posts: [Post]
}
type Post {
id: Int!
title: String
author: Author
votes: Int
}
type Query {
posts: [Post]
author(id: Int!): Author
}
What should the queries look like to associate a post with the author? Is this where connections come into play or is that something else? Here is my attempt at trying to solve the problem but to avail.
mutation createAuthor {
createAuthor(input: {
id: 123
firstName: "Bob"
lastName: "Smith"
}) {
id
firstName
lastName
}
}
query listAuthors {
listAuthors {
items {
id
firstName
lastName
}
}
}
mutation createPost {
createPost(input: {
id: 12345
title: "Title"
votes: 345
author: {
lastName: {
contains: "Bob"
}
}
}) {
id
title
votes
author {
id
firstName
lastName
}
}
}
Any help on this would be appreciated. My Goal is to Query an author and return all of the post's associated with that author as well as create a Post Mutation that adds a post to an author.
There are 2 questions in one, so I'll answer in the order there were asked.
1. return all of the posts associated with an author
Your schema looks correct. The query would look like:
query {
author(id: 1) {
id
posts {
id
title
}
}
}
2. create Post and attach to an author
In your example if you want to expose an interface to create a Post, then you would have to expose a mutation field in your schema
e.g:
type Mutation {
createPost(input: CreatePostInput): Post
}
if you want at the same time of creating a post, to also attach it to an author then you could add the authorId as part of the input, here we only want to attach the Post to an existing Author:
input CreatePostInput {
title: String
authorId: ID!
votes: Int
}
of course this is only the interface definition. We need to actually create the Post and link it to the Author inside the resolver.
The mutation query will look like:
mutation createPost {
createPost(input: {
title: "Title"
votes: 345
authorId: "authorId1"
}) {
id
title
votes
author {
id
firstName
lastName
}
}
}
Hope that helps!

Resources