Nested resolvers and relational data in graphql

by Sai gowtham3min read
Nested resolvers and relational data in graphql

In this tutorial, we are going to learn about how to create relational data and nested resolvers in graphql.

Note: If you don’t know about GraphQL then refer to my previous tutorial GraphQL intro for the beginners

Relational data means consider we have a ‘todo app’ with users and todos where each todo is created by the particular user.

sample-data
let todos = [
    {
        id: 1,
        title: "This is my todo",
        body: "sample content in id 1",
        userId: 1
    },
    {
        id: 2,
        title: "This is my second todo",
        body: "sample content in id 2",
        userId: 1

    },
    {
        id: 3,
        title: "This is my third todo",
        body: "sample content in id 3",
        userId: 2

    }
]


let users = [

    {
        id: 1,
        name: "sai"
    },
    {
        id: 2,
        name: "gowtham"
    },
]

if any user asks for their todos we only show the todos created by them using some type of relationship between the user and todos.

Let’s start writing code.

Type definitions

type Todo{
    id: ID!
    title: String!
    body: String!
}

type User{
    id:ID!
    name:String!
}

type Query{
     user(id:ID!): User!
}

We created two object types which are Todo & User and One Query Type.

Resolvers

Next, we need to tell the graphql how to resolve the user field in the query.

const resolvers = {
    Query: {
        user(parent, args, ctx, info) {

            if (!args.id) {
                throw new Error('id is required')
            }
            return users.find(user => user.id === +args.id)
        }
    }

}

Let’s test it now by using the graphql play-ground.

user

Relational data

In this step, we are creating a relationship between the user and todos for this we need to add a new field called todos to the User type.

type User{
    id:ID!
    name:String!
    todos:[Todo!]!
}

if you ask for a todos you will get an array of todos where it’s shape should look like Todo type but we don’t have any resolver for the todos field.

Nested Resolvers

Let’s create a nested resolver to handle the todos field.

const resolvers = {
    Query: {
        user(parent, args, ctx, info) {

            if (!args.id) {
                throw new Error('id is required')
            }

            return users.find(user => user.id === +args.id)

        }

    },
    User: {
        todos(parent, args, ctx, info) {

              //parent is the root object (User is the parent here)

            return todos.filter(todo => todo.userId === parent.id)
        }
    }

}

In the above code, we have added Nested todos resolver on the User object so that if any user asks for there todos we need to take the id from it’s parent and return their todos.

output graphql user id 1

output graphql user id 2

Note: Nested resolvers only run when we query for that nested field otherwise it doesn’t run.

Code repository