![Server-Side GraphQL in Node.js](https://static.frontendmasters.com/assets/courses/2019-11-25-server-graphql-nodejs/thumb.webp)
Check out a free preview of the full Server-Side GraphQL in Node.js course
The "Query Types Exercise" Lesson is part of the full, Server-Side GraphQL in Node.js course featured in this preview video. Here's what you'd learn in this lesson:
After Scott walks through the code repository and specifies which files will be updated over the course of the workshop, students are instructed to create a query type based off an array.
Transcript from the "Query Types Exercise" Lesson
[00:00:00]
>> Scott Moss: Cool, so now it's your turn. So, I'm gonna walk you through the repo, right click. So you can kind of see what's going on. So couple of things in this repo, if you pull it open, if you not, just follow along with me. You're gonna have two main folders here.
[00:00:14]
You gonna have API folder, you gonna have a client folder. The client is when we get to the clients side of stuff, so not today. But API folder is where you're gonna be doing all the work today. And to around this folder, you're gonna see a source, you're gonna see some tests, and if you create a demo file, you'll see that pop in a source.
[00:00:31]
I wanna show you the database right quick because this is something you won't have to touch. But I want you to know about it. So you know what's happening. So it's not just magic. We're not actually using a real database because I think getting everyone set up on the same database and having that dependency is just a lot mental overheard that gets in the way of learning GraphQL.
[00:00:49]
So I decided not to have a real database, instead just use an in memory database, which is what I'm doing. And all that is gonna be stored in a db.json file. You'll have a user in there, you'll have some pets. And that's because we're making a pet app that allows you to add pets, and like track their vaccinations, and stuff like that.
[00:01:07]
That's what this app is gonna be. But you won't see that until we get to the client side. You're just building the API for it today. So, all your stuff is gonna be stored in the db.jason. This index file here is where we actually create the models for this database.
[00:01:19]
Again, you won't be interacting, or you won't be having to add any code here, it's just here to show you. And then you have like these models that have query methods on them to find things in the database like findMany, findOne, create, for every single model that you have.
[00:01:35]
And then in this case all you have is a user model and a pet model. That's all we are using. So all this is completely obstructed from you and you won't have to touch it
>> Scott Moss: Any questions on that?
>> Scott Moss: Cool, all right, that was really fast. I just don't want you haven't, think about it.
[00:01:54]
And then it's also inside the source folder, you have the resolvers. You have a schema and then you have a server. So what your job is gonna be for this exercise is your going to have to, let's go back here. Define a query type in your schema. So when I say that I mean go into the schema file and you can see that there's nothing in here.
[00:02:15]
It's literally nothing in here. You need to define some stuff. And what do you need to define? Well, if you go into the database. You look at the schema.JSON. You'll see a user schema. So this is the shape that the database is expecting the user to be. So these types of fields, you also need to define a pet type.
[00:02:33]
And here's the shape of what the database expects a pet to be. So based off the shapes that I put in JSON, you need to create them in GraphQL on your schema. So use this as a model to create your types in GraphQL. So look at these and create those types.
[00:02:48]
And then you need to create a query type for getting an array of pets. So I should be able to retrieve an array of pets based off of some queries. So you got to make that query type. And then you need to create the resolvers for that query inside the resolvers file.
[00:03:11]
So if you go here you can see that the query object is empty. So whatever you call your query for getting an array of pets, you'd have to put that here and have that function actually return the value of the pets.
>> Scott Moss: And then from there, the last thing you have to do is actually get your server up and running.
[00:03:30]
So if you go to server js, you can see this Apollo server instance is empty. You're actually gonna have to pass in your type definitions and your resolvers here to get this to execute cuz we said the minimum you need to create a server are gonna be type definitions and resolvers.
[00:03:44]
I believe they're already imported up here. So it's really simple to just add them right there. So what I'm gonna do is I'm gonna walk through one example of using the in memory database so you understand how that works. Then, I'll kinda let you go. So, if you were hopping to one of these resolvers, I'm just gonna make one right quick.
[00:04:04]
We're gonna talk about some of the arguments here and the resolvers. So the first argument that you are gonna get in a resolver is gonna be called the initial value. I'm putting an underscore here and that's because I don't wanna go too deep into this until we get to relationships.
[00:04:22]
But this is what's called a top level resolver as in. There's there's nothing resolving before this resolver that sounds super complicated, but the way you can figure that out is based off your schema because this field exists on the query object. I can be guaranteed that there is nothing that's resolving before it.
[00:04:41]
For instance, if I were to have a field that resolve the user, and then the user had a field called email, and I was resolving the email field, well I can be sure that the email field got resolved after the user object did. So therefore, there was a parent resolve before it, and that's what this value would be.
[00:04:58]
It would be the value that came before it. In this case, there's nothing before this demo, because it exist on a query type, there is nothing before it. The root level was over, you can think of it that way. So it's initial value it's probably gonna be no, unless you set it to something on the server object, which we didn't talk about.
[00:05:15]
But you could, you could go to the server object here, and you can set an initial value in here, and that initial value will be the first argument to every top level resolver. But we didn't set one so it's always gonna be no, someone's gonna put a placeholder here for underscore.
[00:05:29]
The second argument in here is gonna be actually called arguments. So when we get to the point of using arguments inside our mutations and our queries, this is where they're gonna be passed. So this allows clients to send up variables with their queries so you can do things like patternation or filtering and sorting.
[00:05:45]
That's where this is going to happen. We're not doing that right now. And then this next thing right here is going to be what's called the context object. So the context object is exactly what it sounds like. It's, shared context amongst all your resolvers basically, and the way you can do that, so you go into the server.
[00:06:07]
You do this object like this.
>> Scott Moss: You pass a context field like this, which is a function. And whatever you return here, that's gonna be the context.
>> Scott Moss: So what you should do if you want to access the models, and this is what I recommend. I recommend grabbing these models from the database and passing them on a context like that, that way you have access to them inside your resolvers via the same key models.
[00:06:40]
You don't have to do that way. I mean, you could just import the models at the top of the file and use them. That's up to you. The reason I like to pass them in like this is because when you get the testing, you can just mock\g all this stuff out.
[00:06:49]
By overriding the arguments, if you import it then now you're relying on the testing framework to help you out with mocking stuff out and it gets more complicated. So I like for my resolvers I normally don't import anything at the top of the resolver files, I try to just pass everything in via the context.
[00:07:06]
That way I have complete control over marketing demo. So something you either way you're gonna need access to the models and your resolvers. And once you have that, it's as simple as in your case since we're gonna be doing pets, you're gonna say models pet, and there should be like a fine, mini on there.
[00:07:22]
Something like that. And find many takes an object that filters things out by properties. If you don't pass anything, I think it returns everything. So that's what you're gonna be interested in. So how you do that it's totally up to you. There's no right there's no wrong. It's totally up to you get lost in it.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops