What is the difference between graphql-js buildSchema
and the apollo-server gql
? They appear to do a very similar job.
Firstly note, apollo-server's gql
is actually a re-export from graphql-tag. graphql-tag
is a ~150 line package who's default and pretty much only useful export is gql
.
Quick bit of background: the graphql-js
package provides an official reference implementation of GraphQL in Javascript. It provides two important things basically:
graphql
function, which will process any GraphQL query against a GraphQLSchema
object (the GraphQLSchema object is how graphql-js represents your parsed schema).GraphQLSchema
objects used by the graphql
function from strings.Now, this is the part that ultimately confused me: in graphql-js
, taking a string and turning it into a GraphQLSchema
object is a two step process:
parse
function).buildASTSchema
function).It is like this is because the AST (Abstract Syntax Tree) is useful to a bunch of other tools which aren't even necessarily aware of GraphQL (for example see https://astexplorer.net/), where as the GraphQLSchema is only meaningful to graphql-js and related softwares.
graphql-js exposes the functions for doing both steps and these are reused by downstream implementors (like Apollo). buildSchema
is just a convenience wrapper to combine these two steps. It's literally this:
/**
* A helper function to build a GraphQLSchema directly from a source
* document.
*/
export function buildSchema(source: string | Source): GraphQLSchema {
return buildASTSchema(parse(source));
}
The output of gql
on the other hand is just the AST part, which is the same as the output from the graphql-js parse
function. gql
doesn't return a GraphQLSchema
directly for the reason stated above: the AST is useful (note gql
is also doing some basic stuff like stateful caching and will merge an array of schema string into a single AST result ...). Eventually the AST will have to be turned into a proper schema though, and apollo-server does this when the server is instantiated (presumably).
To show the relation, we can take the output of gql
(same as parse
) run it through buildASTSchema
(like buildSchema
does) then pass it to graphql
and it works the same:
import { graphql, buildSchema, buildASTSchema } from 'graphql';
import { gql } from 'apollo-server'; // equivalent to 'import gql from graphql-tag'
const schemaString = `
type Query {
hello: String!
}
`;
const a = buildASTSchema(gql(schemaString));
const b = buildSchema(schemaString);
graphql(a, '{ hello }', { hello: () => 'Hello world!' }).then((response) => {
console.log(response);
});
graphql(b, '{ hello }', { hello: () => 'Hello world!' }).then((response) => {
console.log(response);
});
Gives:
{ data: [Object: null prototype] { hello: 'Hello world!' } }
{ data: [Object: null prototype] { hello: 'Hello world!' } }