This lesson is for PRO members.

Unlock this lesson NOW!
Already subscribed? sign in

Write a GraphQL Schema in JavaScript

5:38 JavaScript lesson by

Writing out a GraphQL Schema in the common GraphQL Language can work for simple GraphQL Schemas, but as our application grows, or when we start using more complex types like interfaces or unions, we find that we can’t use a GraphQL Language file in the same way as before. In this video, we’ll learn how to translate a GraphQL Schema written in GraphQL into a GraphQL Schema written in JavaScript.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

Writing out a GraphQL Schema in the common GraphQL Language can work for simple GraphQL Schemas, but as our application grows, or when we start using more complex types like interfaces or unions, we find that we can’t use a GraphQL Language file in the same way as before. In this video, we’ll learn how to translate a GraphQL Schema written in GraphQL into a GraphQL Schema written in JavaScript.

Avatar
p4bloch

Could you please elaborate a bit on why using JS to describe your schema is better than using GraphQL Language directly? Interfaces and Unions can also be defined using the QL. Thanks!

Avatar
Josh Black

That's a great question, and I think the answer is that it's not necessarily better. It most likely depends on your use-case, whether or not you're starting a product/service from scratch or not, and how much control you need in resolvers.

I think a key constraint of GraphQL JS is that the buildSchema utility will not let you define proper resolvers for Union/Interface types that you define in the GraphQL Language. There are definitely ways around this limitation, and Apollo is doing a great job of demonstrating that. In Apollo-related projects they actually have you define your schema in the GraphQL Language, and then you define the resolvers separately, much like you described above.

I think this approach is awesome, and can make things incredibly simple to get up and running so if that's what you want to do definitely go for it. From another perspective, if you're creating a GraphQL Schema and you want to implement a middleware-esque pattern on resolvers then you might want more fine-grained control of your schema. You might also want to leverage existing JS-tools that you have, such as codemods, in order to maintain your codebase and bring it along with you as your product/service/company grows.

At a high level, I think that covers why you might want to use one or the other. I think they're both great strategies, and one can make whichever approach they choose work for their use case. Hope that helps!

In reply to p4bloch
Avatar
p4bloch

Thanks for such a detailed response, you surely cleared out some doubts I had. I indeed used Apollo's graphql-tools's makeExecutableSchema function. I believe graphql-tools as a project itself is intended to be used without having to use the rest of Apollo server's middlewares so maybe it is useful as a mere replacement of buildSchema as well.

I definitely were not aware of buildSchema's limitations, thanks for pointing that out.

I understand that in a complex application you might want to have the schema be more malleable than just strings, but I wonder how far you can actually get without it. Definitely the GraphQL JS limitations are a quick deal breaker (maybe because of its reference implementation nature?), but Apollo seems to be doing a much better job on making GraphQL production ready tools for Javascript.

Ultimately I would expect not having to worry about how the schema is defined (and use the much clearer and generic GraphQL notation) but instead having the resolvers layer to be able to handle any complexity that may arise beyond that schema.

Thanks for the course Josh, a very valuable GraphQL resource :)

In reply to Josh Black
Avatar
Josh Black

Ultimately I would expect not having to worry about how the schema is defined (and use the much clearer and generic GraphQL notation) but instead having the resolvers layer to be able to handle any complexity that may arise beyond that schema.

Totally understand this, and am so thankful for Apollo for building out the tools to allow this 😄

If you're curious, should definitely try out Elixir or Scala's GraphQL implementations just to see their perspective on this stuff as well!

Also, thank you so much for watching! I'm so glad it was helpful!

In reply to p4bloch

We look inside of our index.js file and look at how we're defining our schema. What we're doing is using the build schema function, passing in a template literal to define our schema as a string.

However, what we can do is build out this entire schema definition using JavaScript. Let's try that.

The first thing that we're going to need to do is change this require statement to grab some of the functions that we need.

The first one's going to be GraphQL schema so we can actually write out our schema. The second one's going to be GraphQL object type for our higher order types. Then finally we can grab GraphQLString, GraphQLInt and GraphQLBoolean as some primitive types in GraphQL.

Now let's take all of these types and start rewriting our schema. The first thing we can do is say con schema equals new GraphQL schema. What we do is we pass in this configuration object that takes in a couple of keys.

In this video, what we're going to be focusing on is the query type, and we'll actually go and make a variable in an second. But we can also pass in mutation as a key, as well as subscription to represent other kind of capabilities of our GraphQL server.

Now let's actually go into find our query type. This query type is going to be a new GraphQL object type. I'll take in that same kind of configuration object that the schema did.

The first field that we'll define on it is name, which is query type. We can also add in optional description, and in this case, we'll just add a description of the route query type. We can also add a key called fields, which will define what the things are that we can query for in our GraphQL schema.

Let's go ahead and add a video field. Inside of this field, we need to specify the type, which will be video type, and we'll define that in a second. Then we'll also add in a resolve field, which will just be a function that will return a promise. This promise is just going to resolve with a simple object.

We're going to use this object to just represent a video, so we'll add in some of the fields that we need, such as ID, title. We can also add in duration, and finally, watched.

The idea behind this structure is that we're going to have all of these fields and each field has a type and a resolve statement. What the job of the resolve statement is is to provide a function that can return something asynchronous like a promise, and it will actually resolve with the information that we need to resolve this field.

Now that we know how those statements work, let's actually go and write out our video type.

Our video type follows a very similar structure to our query type, where we're just building it off of a GraphQL object type. We also give it a name, in this case it'll be video. We'll also give it a description, which will be A Video on Egghead.io. It also has fields that we can query for on this type.

The first field that we're going to add is ID, and the type of ID is going to be GraphQL ID. Let's actually make sure that we're grabbing that from the GraphQL package at the top of our file.

Next up, we can add a description, and in this case, it's going to be the ID of the video.

Next up, let's add the title, which would be very similar, except now the type is a GraphQLString and the description part is going to be the title of the video.

We can also add the duration, which will be a GraphQLInt. The description's going to be the duration of the video in seconds.

The last field that we're going to add is watched, which is just a GraphQLBoolean. We'll grab that and then then description is going to be whether or not the viewer has watched the video.

Now that we have our video type defined and we have all of these fields defined on it, including ID, and title, duration and watched, we have our query type that's telling us what kind of fields are available for us to query on. We actually have a almost complete representation of our original schema that we defined using build schema and the resolvers.

Let's actually try and get rid of this schema that we have as well as the resolve statements that we created before, and use this new schema that we created with the GraphQL schema constructor inside of our server.

First, we can remove the root value and then we can switch into our terminal and run node index.js to start our server. Then we can switch out of full screen here, bring in our window, and run Enter and actually visit our graphical editor.

Inside of here, we can query for our video type, we can get the ID, title, duration and whether or not it was watched. We'll execute the query and we get a response.

HEY, QUICK QUESTION!
Joel's Head
Why are we asking?