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!

Wednesday, 9 September 2020

Azure Functions with TypeScript

Things to know about using TypeScript with Azure functions:

  1. Make sure that you have node installed using the latest LTS version (Long Term Support). If you need the latest version for other projects try using nvm-windows to manage multiple versions of Node. Install the latest version of nvm using the zip file in assets of the latest release. nvm list and then nvm use. Also nvm install v 64/32bit is pretty nifty.
  2. To run Azure functions manually (particularly useful for timers etc.. anything that is not an Http Trigger). http://localhost:<port>/admin/functions/<FunctionName>. Also for CRON timings see this cheatsheet.
  3. Azure Functions in TypeScript still use CommonJS modules, so while you can use imports and exports in your code the transpiled JS will be using Node style modules. Bear this in mind if you are expecting to be able to use any of your own libraries that compile to anything other than CommonJS. Check your TSConfig.
So is TypeScript support any good? So far it seems good, the only problems are with my own libraries. I have also noticed that you cannot use fat-arrows for Azure Index functions (for those not so familiar - the entry point called by Azure infrastructure).