Tuesday, 29 September 2020

Defining a GraphQL Schema in TypeScript

Basic Example

In the documentation you will see something like this:

  import graphQL from 'graphql';
  
  // Construct a schema using GraphQL schema language
  export default graphQL.buildSchema(`
    type Customer {
      dob: String
    }
  `);
This is great for getting familiar with graphQL initially but what happens when I want to use a type that is not native? For instance, graphQL, out of the box, has only 4 "scalar types" - String, Int, Float and Boolean. 

So what if I want to deal with a date from my data source? Well there are a few things to know: regardless of the storage format graphQL will change it to a "Long Seconds" number (actually the number of millisecond's elapsed since 01-01-1970). Sure you can plug that into new Date on the frontend, but it is a potentially unnecessary cost for the browser in terms of performance and would mean that we must rely on the consuming developer to remember to tidy up our dates.

Diving in further

Such a limited number of Scalar types in graphQL does seem to invite extension and so we have "graphql-scalars". It does exactly what we want:
{
    "name": "Lewis Kinsella",
    "dob": "1994-09-02"
}

However, further inspection of the docs plus also the common use case test in the code base shows that this library works differently. Instead of using buildSchema we have "makeExecutableSchema" with some typeDefs and resolvers.

import gqlTools from 'graphql-tools';

const schema = gqlTools.makeExecutableSchema({
	typeDefs,
	resolvers,
});

So how do I change my existing work to fit with this?

Let's start at the end...

app.use('/graphql', graphqlHTTP({
	schema
});

It looks like resolvers are no longer added as the "root value" argument in the graphqlHTTP object.

Instead we are adding the schema object only. How do we make that?

const schema = gqlTools.makeExecutableSchema({
	typeDefs,
	resolvers,
});

The typeDefs here is mostly what we had before except now we need to merge in our extra scalar functionality.

a) resolvers are merged with the scalar tool resolvers.

const resolvers = gqlTools.mergeResolvers([root, scalarResolvers.resolvers]);
and
b) 
const typeDefs = merge.mergeTypeDefs([customTypeDefs, ...scalarTypeDefs.typeDefs]);

Where customTypeDefs is what we had at the beginning, no need to change it, except to add some extra scalar types!

 import graphQL from 'graphql';
  
  // Construct a schema using GraphQL schema language
  export default graphQL.buildSchema(`
    type Customer {
      dob: Date
    }
  `);
Happy graphQL-ing in TypeScript with Scalar types!

No comments:

Post a Comment