Server-Side GraphQL in Next.js

Resolving Nested Objects

Scott Moss

Scott Moss

Superfilter AI
Server-Side GraphQL in Next.js

Check out a free preview of the full Server-Side GraphQL in Next.js course

The "Resolving Nested Objects" Lesson is part of the full, Server-Side GraphQL in Next.js course featured in this preview video. Here's what you'd learn in this lesson:

Scott demonstrates how to create a resolver for a nested object, such as a person's pets, and explains the importance of only querying the database for the nested object when it is requested in the GraphQL query. Scott also clarifies the concept of the parent object in resolvers and mentions that the order of resolvers within an object does not matter, as long as the names match.

Preview
Close

Transcript from the "Resolving Nested Objects" Lesson

[00:00:00]
>> Scott Moss: Resolving interfaces is literally the same thing, as resolving unions, there really isn't any different thing here. You do a resolve type in this case the interface and you do a if check on the object to see which one it is, and then you return the name of it.

[00:00:16]
It's pretty much the same thing, it's no different. Resolving nest objects. I think we kind of already walked through that with the person. Did we do that? No, I guess I didn't do that. I did like a field level. So let's talk about nested objects. So with nested objects, we can go back to our schema, and then we can say like a person has pets, which are type animal like this.

[00:00:38]
So this will be a nested object. So now if I search for people, I can get the pets from them. So what I could do is, let's say a really classic example would be something like this. So for a person, or where is it at? Here we go for people, so let's say people have pets, right?

[00:00:58]
So in this case I I'll return for pets, an array of IDs, right? I'll have pet ID 1, pet ID 2, pet ID 3. I have three pets here with their IDs. This wouldn't satisfy the request if I asked for pets right now, right, because pets are a object type.

[00:01:16]
So if I said give me people.
>> Scott Moss: And I want the name, and I want my pets, and then inside of pets I want the name. Try to run this.
>> Scott Moss: It's gonna say, I could not get animal.name. It's a non nullable field and you just return an array of IDs or numbers, I don't know what to do with this.

[00:01:36]
So how can I solve this? Well, I guess you could in here in your database query to this person, you could say, hey, join the table, give me all the pets too. But if you did that, you'd be doing that for every single query that someone sends up regardless they ask for pets or not.

[00:01:50]
Maybe you should only be joining the table if they ask for the pets, right? So if I went in here and was like, yeah, always send back the pet objects for this user, no matter what. What if my query did not have pets? Your database query is still getting the pets.

[00:02:06]
That's kind of wasteful and redundant and defeats the purpose of GraphQL. So what you wanna do is only query the pets when the query asks for the pets. Let me repeat that. Only query the database for your pets when the GraphQL query is asking for the pets. So how do you do that?

[00:02:24]
It's quite simple. You let GraphQL handle it and you make a resolver for it. If you make a resolver for it, GraphQL will use that resolver when someone asked for it. It's that simple. There is no resolver for pets on a person, so it didn't use it, it just took what you gave it, in this case an array of numbers.

[00:02:41]
But if we go to our person which is what is returned from the people query and and I say pets here and I make a function and because its gonna have a parent here which is actually gonna be a person, so am gonna call it person. In a real life scenario, I would loop over these person.pets IDs and go to the database and say, give me all the animals with this id, right?

[00:03:09]
So I'm just gonna imitate that and return an object of animals which have species and name, right? So I'll just say dpecies
>> Scott Moss: Cat and then there are and just to be super clear, I'll just return one Id even though that's not gonna matter. So in this case I'm saying cool.

[00:03:35]
I know that when I run this query so I'm just gonna return the pet IDs cuz I have them on the table already maybe. But I don't wanna join the table unless someone actually asks for the pets. And if they do ask for the pets, GraphQL will then run person.pets, which will get the current person that was previously resolved and go to the database and get the pets for them.

[00:03:56]
And if I return many people, then this will be called for each one of those persons singularly, right? So now if I run this, I should be able to get the pet's name. You could probably see this is very powerful and it's way different than any of the server architecture API, that you've might have built it.

[00:04:16]
It's just a different way of thinking. You actually have to think as a graph. Looking back when I started learning GraphQL, like 2015, 2016 maybe, the thing that really confused me was this nature of what is the parent? How do I know when there's a parent? If you are making a resolver for a object type, there's always gonna be a parent here, because you're only this is only ever gonna get called when the object type is trying to be resolved.

[00:04:48]
So there probably is always going to be a parent here if you're resolving for object type, there almost is never going to be a parent when you're resolving from a query type or a mutation type because they're on the route, nothing happens before them. That's the entry into, this is the only way you can interact with your GraphQL API is by calling a query or calling a mutation.

[00:05:08]
You can't just go to the GraphQL API and like, give me person. It doesn't work that way. You have to add that to a query somewhere. So therefore, this is the first thing to run. So there is no parent here. But if an object type resolvers are running, that means, somewhere earlier, maybe from a query, maybe from a mutation, a person is being returned somewhere.

[00:05:29]
And now, because I have these fields, it's resolving the individual fields of that person. So therefore, there is an object above it, which is a parent.
>> Speaker 2: Does the order of the arguments in the resolver matter, for example, does the person have to come before the pets, so that it can resolve the person first.

[00:05:47]
>> Scott Moss: No, the order in which you make the resolvers in this object does not matter. And in fact, in Javascript, order inside of objects cannot be maintained or guaranteed. There is no such thing as order in the object. JavaScript does a really good job of, if you were to log this object out, it'll log at the same order that you made it.

[00:06:03]
But order inside of an object is not guaranteed. That's the point of an array. So where you write this does not matter. It's all about the name. This name matches with this name. This name matches with this name. That is the only thing that matters.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now