GraphQL-JS: The hidden features
Jonas Helfer
Last week I wrote a post about how GraphQL makes mocking your server API really easy. Some people have asked me what I’ve used to build that, because the schema looks quite different from what they are used to seeing with GraphQL-JS. The answer is: I used GraphQL-JS!
In case you are new to GraphQL: GraphQL-JS is Facebook’s reference implementation of the GraphQL spec, and a library that you can use to build your own things with GraphQL. Most people are not aware of the second part, and that’s what this post is about.
What is GraphQL-JS?
GraphQL-JS is the reference implementation of the GraphQL spec, but it’s also a library of useful tools for building servers, clients and tooling for GraphQL.
If the library aspect of GraphQL-JS is news to you, that might be because it’s not documented at all! I’ve you’ve been using GraphQL at all, chances are that you used the only function that’s documented: graphql(schema, query).
If you look under the hood, though, you will notice that GraphQL-JS exports a lot more than that one function, and some of the things it exports are really useful for building your own GraphQL servers, clients and tooling.
This post is going to be a quick tour of a few of the most useful functions that GraphQL-JS exports.
Because there’s not much documentation, for each function I’ll include a code snippet for how to import it, and a link to the source code, which you can inspect to see how to use that function.
parse
import { parse } from 'graphql';
You’re probably not surprised that GraphQL-JS exports a parser that you can use to parse queries. But did you know that it can also parse the schema notation? That feature was added recently in version 0.5.0, and it is incredibly useful. It means that with a little tooling you can now write this:
type Book { id: ID! title: String authors: [Author] }
instead of this:
const Book = new GraphQLObjectType({ name: 'Book', fields: () => ({ id: { type: new GraphQLNonNull(GraphQLID) }, title: { type: GraphQLString }, author: { type: new GraphQLList(Author) }, }) }
The first one is a lot more readable, right?
introspectionQuery and buildClientSchema
import { introspectionQuery, buildClientSchema, } from 'graphql';
Did you ever wonder what query GraphiQL sends to the server to learn about its schema? It’s quite a long and intricate query, but lucky for us, it’s also exported by GraphQL-JS. BuildClientSchema can take the output of the introspection query and build a schema out of it, which you can then use to do various things, such as validate queries before sending them to the server. Keep in mind that it’s not exactly the same as the schema on the server, because the introspection query doesn’t tell you about resolve functions and other things that are needed for executing a query.
printSchema
import { printSchema } from 'graphql';
Do you ever get confused by all the curly braces and parentheses in your server schema? I certainly do. If you do, too, you might want to consider using printSchema to print your schema in the shorter form.
If you use its sibling printIntrospectionSchema together with introspectionQuery, you could even print the schema of any GraphQL server that you are curious about. For example, you could point it at GraphQL-hub to find out what its Twitter, GitHub or any of the other schemas look like. If you don’t already know GraphQL-hub, you should go check it out, it’s an open-source project that lets you query popular APIs (Twitter, GitHub etc.) with GraphQL!
validate and execute
import { validate } from 'graphql'; import { execute } from 'graphql';
The main graphql function from the documentation is really convenient. Given a schema and a query it validates the query and then executes it. That’s great, but sometimes you might only want to validate or execute the query — not both — and that’s precisely what validate and execute are for.
Validate, for example, can be used to validate a query on the client before sending it to the server, which can save some time if the query is invalid, and it can be easier to extract error messages from, because the errors don’t have to be serialized.
Execute on the other hand could be used without first calling validate when you’ve pre-validated all of your queries. Apparently this is what Facebook does: their GraphQL queries are sent to the server and validated at build-time. If the query is valid, the server stores it and returns a unique identifier for it. At runtime, instead of sending the whole query, the clients just send that unique identifier, which is much more compact. Because the server already knows that the query is valid, the validation step can be skipped.
buildASTSchema
import { buildASTSchema } from 'graphql';
Source code for buildASTSchema.
A bit earlier I wrote that with the new parser and a little bit of tooling you can build your entire schema from a shorter notation. BuildASTSchema is the other crucial part there. Parse produces an AST, and buildASTSchema turns that AST into a GraphQLSchema.
The only thing that’s still missing for it to be an executable schema is information about resolve functions — and depending on your schema also resolveType for interfaces, and a few other things.
I’ve written a little tool kit called graphql-tools which does exactly that (and a few more things). You can use it to add resolve functions to a schema that was created with buildASTSchema. If you’re interested, you can check it out on GitHub and install it from npm.
Conclusion
GraphQL-JS is not just a reference implementation, but also a library of incredibly useful tools. It has a lot more to offer than the current documentation on GitHub shows.
I’ve only scratched the surface here — there is a lot more in GraphQL-JS — but I hope it gave you a glimpse of the myriad possibilities. I can’t wait to see all the great things that people are going to build with it!
If this post has piqued your interest, you should definitely check out the excellent “GraphQL source-code overview” by Lee Byron on Youtube, and take a look at the source code yourself!
This post is part of the publication Building Apollo, where Sashko Stubailo and I regularly write about GraphQL and the new data stack we’re working on, called Apollo.