GraphQL scalars and their input and result coercion

When designing GraphQL schema we have to define the so-called primitive values of each query. In GraphQL the primitive values are represented by scalars and enums. The GraphQL specification has different built-in scalars. In this first part of this series we will concentrate only on the built-in scalars. For the purpose of demonstrating real applications of the built-in scalars we will apply them in a modeling query for retrieving tasks from the existing “in-memory” database and also for adding new tasks to a database.

Introduction

In GraphQL we deal with 8 different types:

In the article Input object type as an argument for GraphQL mutations and queries we were focusing on objects and input objects. In this series we are moving to scalars and enums. In this first part we deal only with built-in scalars; enums and custom scalars will be topic of the next part.

Checkout the upcoming free GraphQL language course with in browser exercices
From upcoming GraphQL Language course

When we query or mutate data using our GraphQL schema, we first have to understand two operations that occur in GraphQL servers. These are:

  • result coercion — upholding the contract of a type which we receive from the server (basically upholding the primitive values or object type)
  • input coercion — upholding the contract of a type for input arguments that we pass into the GraphQL query or mutation

To fully understand the algorithm behind the coercion we have to go into the GraphQL specification. For us, the simple explanation as above is enough to get started. It is important to recognize that the rules for each scalar type are different, therefore we have to discuss these rules for each type and for each result and input coercion.

GraphQL scalars

Scalars are primitive values in GraphQL. This means that if we imagine each GraphQL response as a hierarchical tree graph, we can call the primitive values “leaves” in terms of graph theory. To imagine, check out the visualized hierarchy tree graph of our response for our query getTasks and mutation addTask, which we will code in this short tutorial series

the hierarchical tree graph of the response for our queries and mutations

In this first part we will deal only with id, name, completed, progress and taskPriority as these are represented by built-in types. In the second part we then extend the Task type with the fields updatedAt, createdAt, and state.

Built-in scalars

In this list we will go through each default scalar type. We will also discuss rules for result and input coercion and where this scalar should be used.

ID

The ID scalar type represents a unique identifier, often used to refetch an object or as a key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as "4") or integer (such as 4) input value will be accepted as an ID.

If you use, for example, some caching client like Apollo, each type should have at least one ID. This allows us to perform a normalization of queries, making it possible for us to update things in Apollo internal redux store automatically based on the unique id (edit: Apollo 2.0 does not use redux as its store anymore). This is also performed in Relay by the global identifier at each node. Even that ID is often numeric or in another format such as base64 encoded value. It is always serialized as a string because we want to achieve uniformity across different formats.

Input coercion:

  • 5 is parsed into a string as “5”
  • However, if we pass true, it is not parsed as “true”. GraphQL will raise the following error
Argument \"input\" has invalid value {id: true}.\nIn field \"id\": Expected type \"ID\", found true

the same case is even for the Float type and etc.

Argument \"input\" has invalid value {id: 3.00}.\nIn field \"id\": Expected type \"ID\", found 3.00.

Result coercion:

If possible the ID is serialized into a string.

  • 6 is serialized into “6”
  • true is serialized into “true”
  • 3.00 to “3”

Int

The Int scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2³¹) and 2^31 - 1.

Input coercion: string “10” will raise an error when passing it as a GraphQLInt argument. Also 10.00 will raise an error. Only pure Integer values are accepted.

Result coercion: The string “3” is serialized into 3 and float 3.00 is also serialized to 3.

Float

Input coercion: String “3” or “3.00” will raise the error in the same way as with GraphQLInt. When we pass 3 as an integer it is parsed into 3.00.

Result coercion: 3 is serialized into 3.00, “3.00” is serialized into 3.00, etc.

The Float scalar type represents signed double-precision fractional values as specified by IEEE 754.

String

The String scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.

Input coercion: The rules are similar for GraphQLID. The input 5 will raise an error etc.

Result coercion: 1 is serialized into “1”, 1.00 is serialized into “1” , true is serialized into “true” ,etc.

Boolean

Input coercion: When we pass “true” as an argument, it raises an error.

Result coercion: If possible, all non boolean value are coerced into boolean values. The example can be 0 and 0.00coerced intofalse as well as 1 and 1.00 serialized intotrue. However, it is important to emphasize that string "true"or "True" is not coerced into true. GraphQL schema will allways return boolean true value for every string with the length greater than 0.

The Boolean scalar type represents true or false.

An application of built-in scalars

Now let’s go right into implementation. You can follow the code snippets in this article or clone the git repository

git clone https://github.com/a7v8x/express-graphql-demo.git -b feature/3-graphql-scalars

If you are new to GraphQL, it may also be helpful to check out previous articles in GraphQL mastery publication, especially the one on creating mutations as we use them as prerequisites for this article in terms of understanding GraphQL. We will also use parts of the code that we built in previous articles. However, everything can be obtained from the mentioned repository. In the GitHub project we do not use a real database. The in-memory database is enough to get started.

To demonstrate each type of built-in scalar, let’s design a Task object type in the following way.

In our code we use graphql-js library. Then we can describe Task type as follows.

Now let’s create a simple array where we will store our seeded tasks. Then we can make the simple getTasks query and the addTask mutation, which we can call from our resolver function in GraphQL schema. The getTasks query is used to query all the tasks from the memory database. The addTask mutation is then used for creating a new task. In getTasks we can demonstrate result coercion. However, it does not have any arguments in our code, so we also needed to create an addTask mutation.

tasksDb.js

The corresponsing GraphQL schema for retrieving tasks from memory db is the following

Query for retrieving tasks

If we used the same implementation of GraphQL server as we discussed in the article on basic setup of GraphQL in express, we have everything we need to perform query for retrieving tasks against the schema. Just go to /graphiql and paste the following query

getTasks.graphql example of the query for retrieving tasks

If you use the Github project code you should get this result

result of calling getTasks query

First, let’s create an input object type for adding a task. We will use some defaultValues for each field

AddTaskInput

Now we can move on to designing the addTask mutation

addTask mutation

We can execute this mutation and add a new task into the “in-memory” database. We can also use variables as we discussed in this GraphQL quick tip or just pass it as an inline argument.

mutation addTask.graphql

The result should be something like this

result of the addTask mutation

For the sake of demonstration, we can now test some rules for result or input coercion. For example, let’s take a result coercion for GraphQLID and test the rule that an integer is serialized into a string.

6 is serialized into “6”

We can change the value of id to 6 in order to test a task in taskDb.js. By calling the getTasks query in GraphiQL in the same way as in the previous case, we will get the expected result, that will confirm this rule

In the similar way we can confirm some rule for input coercion. Let’s take for example rule for input coercion of GraphQLInt.

string “10” will raise the error, when passing it as an GraphQLInt argument

We can demonstrate it on the addTask mutation,

which raises the following error

This proves the rule, that “10” will raise an error with input coercion on our addTask mutation

Summary

All built-in scalars can be used as fields (primitive values) for input types as well as for output types. Each built-in GraphQL scalar has different rules for input and result coercion which are useful to know. We can also use enum and custom scalars as we will find out in the next part of this series.

Did you like this post? Then clap for this article as it is easier for others to find it. The repository with the examples and project setup can be cloned from this GitHub branch. You can get early access to upcoming free GraphQL course by subscribing at graphqlmastery.com.