Apollo server: using the GraphQL Schema Language

by

GraphQL and Apollo are two technologies I’m very excited about. In this post I’ll show you how to setup an Apollo Server using the GraphQL schema language. There are other approaches on how to implement your schema. In another tutorial I’ll show you how to do so using a GraphQL-JS Schema.

Getting started

When the server is up and running you should be able to view GraphiQL at http://localhost:8080/graphiql
Copy paste the below text into the upper left box in GraphiQL.

Hit the big play button and if everything works you should receive the answer below.

So what we have right now is a very simple schema that exposes a testString. There is no resolve function for this testString, so how come we get “It works!” back? Apollo have the ability to use mocks. Which means that we can mock return types. If you look at the mocks.js file you’ll see this:

This means that all Strings that cannot be resolved, will be returned as “It works!”.

What makes it work is the addMockFunctionsToSchema()  in the server.js file:

Now  let’s get started writing a GraphQL Schema for your Apollo Server!

The basics

Right now our schema lies in the schema.graphql file. GraphQL files are imported as strings using the babel-plugin-inline-import package.

The schema.graphql file could be replaced by a schema.js file. I’m going to continue using the .graphql file extension, but if you’r more happy with .js files you can see how that is done in this side by side comparison:

Right now we are mocking all String return values with “it works!” when there is no resolver.

Now, that is not really exciting. So let’s add a resolver to change that!

As you can see in the server.js file. Our resolvers are defined as an empty function. The resolvers are the ones responsible for resolving queries to Apollo by doing whatever is nessecary to “resolve” the query and deliver data if requested. Let’s start by creating a new file called resolvers.js and input the following code.

Now we need to import it into our server.js file and change the resolvers used in the  makeExecutableSchema() body

Now refresh GraphiQL and try querying for testString again. We should now get the following response.

So we just created a resolve function for testString. That was pretty easy right? Later we’ll add some models that make more sense.

Splitting up the schema

We still have a pretty simple schema so splitting it up is not really necessary but it’s nice to know that it can be done.

Inside of our data folder, let’s create a new folder called schema.

Inside the schema folder, create an index.js, schemaDefinition.graphql, and query.graphql file. It should look something like this.

graphqlschemafolder

Let’s start with the query.graphql file. In this file we only want what our query should contain. So let’s take the query from our schema.graphql file and insert that into our query.graphql file like so:

Now to the schemaDefiition.graphql file. This one contains the rest of the string from the schema.js file. It should look like this.

The last and most important of the files is our index.js file. This is the one that puts them together and exports them.

Modularizing might seem premature when our schema is this simple, and it is. But as we progress it should make more sense. But by no means do you need to do this. You can keep it all in one file if you want to, like we did in the section prior to this one.

Adding custom models

More often than not your endpoints want to return some kind of model. So let’s make a couple of models. Our GraphQL schema doesn’t need to represent our data layer schema. I’ll get to that later in this section. Let’s start of by making a User model. Create a user.graphql file in our schema folder and paste in the following User model.

Our User has a property called cars which is an array of the model Car. Since we don’t have a car model yet I say we create one right now. Add a car.graphql file to the schema folder and paste the following model into it.

Now to the fun part. Like I said earlier, our GraphQL schema doesn’t represent our database schema. I might not wanna taint my User model by putting an array of cars on it in the database. So how does this work? We setup a resolve function for the cars parameter on the User model. Since every car has an owner, we can search the database for a car with this queried user as owner. The database model might have navigation properties or some other way of navigating to his cars. But we have to remember that this shouldn’t matter to our GraphQL client. In this tutorial we are not really gonna touch the database side of things, I’ll get to that in another tutorial.

Let’s create the resolve functions related to the user so we can see how this could work.

Now I’ve out-commented  db.findUserWithId(id)  and  db.findCarWithOwner(user._id) because those won’t work right now when we haven’t made a connector/model layer for us to fetch models in the database. So I’ve “mocked” them. You should get the picture 😉

The bottom resolver on User is the resolver that is run when you query for something that returns a User where you want the cars array as well. Fields that are not a scalar type are not resolved by default. You need to specify that you want them when you query.

Now for this to actually work we still need to update our query schema. So head into our query.graphql file and add getUser like so.

And as the last thing we need to add our models to the schema as well. We do so in the index.js file inside the schema folder.

Now we should be able to query after a User. Now the parameters we query with obviously doesn’t mean anything since we return the same model no matter what.

So let’s just query with the following.

Our query should change and include all the scalar types of the User model. This means it returns all fields except for the cars property. Try adding the cars to the query and see what happens.

Again our query will expand our cars so we get _id, model and registrationNo returned. But not the owner. Again this is because it’s not returned by default. We need to query after it specifically. But since we haven’t made a resolver for it we won’t do that 🙂
That’s it for this tutorial! Check out part 2 where we add a model and connectors layer so we can get some data persistence!

  • stubailo

    This is an awesome tutorial! If you see anything that can be improved in the official docs as well, let me know!

    • Jesper Christensen

      Thanks Sashko! It means a lot! I’ll keep an eye on the official docs ! 😉

  • tim-soft

    You will need to update the schema location in server.js after splitting things up into the /data/schema folder

    The new import in server.js should be
    import schema from ‘./data/schema/index.js’;

    • Jesper Christensen

      Hi Tim

      Actually, when you import folders like “import schema from ‘./data/schema’;” It by default imports the index.js file inside of that folder. It is a convention i believe originated from Node, but webpack and browserify also follow this convention.

  • Yesterday I spent all day trying to learn Apollo and GraphQL. I thought it was going to take me a while to understand but your 2 part tutorial make is so easy to understand. You sir are awesome!

    On a side note I see you have a TypesScript example on your Github account. TypeScript is the way to go. Again thanks for putting this together.

    • Jesper Christensen

      Thanks for reading and even more for commenting! 🙂

      Yes TypeScript is definitely the way to go 😉 Only did these in JS because then i could follow it up a TypeScript Apollo tutorial 😉