Building Chatty — Part 8: GraphQL Input Types

A WhatsApp clone with React Native and Apollo

Simon Tucker
React Native Training
10 min readSep 26, 2017

--

This is the eighth blog in a multipart series building Chatty, a WhatsApp clone, using React Native and Apollo. You can view the code for this part of the series here.

In the first 7 parts of this series, we put together a WhatsApp clone starting from scratch all the way to MVP.

Where we’re at

Steps

  1. Setup
  2. GraphQL Queries with Express
  3. GraphQL Queries with React Apollo
  4. GraphQL Mutations & Optimistic UI
  5. GraphQL Pagination
  6. GraphQL Subscriptions
  7. GraphQL Authentication

In this tutorial, we’ll focus on adding GraphQL Input Types, which will help us clean up our queries and streamline future GraphQL development in our app.

Here’s what we’ll accomplish in this tutorial:

  1. Discuss writing more flexible GraphQL requests
  2. Add GraphQL Input Types to our Schema
  3. Update resolvers and business logic to handle Input Types
  4. Update client-side GraphQL requests to use Input Types

Writing flexible GraphQL

So far in our journey, writing GraphQL queries has been a breeze. We’ve been able to get all the data we need in a single request in exactly the shape we want with very little code. But APIs inevitably get more complex as apps mature. We need to ensure our GraphQL infrastructure adapts gracefully as we expand the functionality of our app.

Let’s do an audit of the GraphQL queries that currently power our React Native client to look for opportunities to improve our querying….

You may notice the queries, mutations, and subscriptions that return Group types have a similar shape, but don't share any code. If we modify or add a field to the Group type later on, we would need to individually update every query and mutation that returns a Group type -- not good.

If we create a common GraphQL fragment for our queries and mutations to share, we’ll only need to update the one fragment when the Grouptype changes and all our queries, mutations, and subscriptions will benefit:

Step 8.1: Create GROUP_FRAGMENT

Added client/src/graphql/group.fragment.js

Now we can update all these GraphQL requests to use the fragment:

Step 8.2: Apply GROUP_FRAGMENT to Queries with default variables

Changed client/src/graphql/create-group.mutation.js

Changed client/src/graphql/group-added.subscription.js

Changed client/src/graphql/group.query.js

There are a few things worth noting about this pattern:

  1. Changing fields on GROUP_FRAGMENT will immediately apply to all queries, mutations, and subscriptions that use it.
  2. We are occasionally using default values for the $first variable -- $first: Int = 1 to return the first message in a Group if that variable is not specified when executing the query/mutation/subscription.

(GraphQL default variables is without a doubt the greatest and most essential addition to apollo-client of all time, and whoever wrote that PR deserves free beer for life 😉)

  1. Our GraphQL requests have much simpler return shapes, but much more complex sets of variables.

Old CREATE_GROUP_MUTATION:

New CREATE_GROUP_MUTATION:

Yeesh! If we needed to change a variable used in GROUP_FRAGMENT, we'd still have to change all the queries/mutations/subscriptions. Moreover, it's not very clear what all these variables mean. $first, $after, $last, and $before are variables we use to paginate messages within a Group, but those variables need to be specified in USER_QUERY -- that's nonobvious and weird. What we need is a way to abstract inputs to simplify the way we declare variables and update those variables as our app evolves. Enter GraphQL Input Types!

Input Types on the Server

GraphQL Input Types are a super simple concept — you can declare named arguments in a GraphQL request in whatever shape you want.

For example, we can abstract away the pagination variables from our GraphQL requests by adding the following ConnectionInput in our schema:

This will enable us to update Group like so:

This will drastically simplify any request that returns Group types!

We should strive to apply input types to all of our GraphQL requests that have even the slightest complexity in their input requirements. For Chatty, I’ve added input types for most of our mutations:

Step 8.3: Add Input Types to Schema

Changed server/data/schema.js

Sweet! Now let’s update our resolvers and business logic to handle input types instead of individual variables. The changes are minimal:

Step 8.4: Add Input Types to Resolvers and Logic

Changed server/data/logic.js

Changed server/data/resolvers.js

That’s it!

Input Types on the Client

We need the GraphQL requests on our client to match the input type updates we made on our server.

Let’s start by updating GROUP_FRAGMENT with our new ConnectionInput:

Step 8.5: Add Input Types to Mutations

Changed client/src/graphql/group.fragment.js

This will super simplify all GraphQL requests that return Group types:

Step 8.5: Add Input Types to Mutations

Changed client/src/graphql/create-group.mutation.js

Changed client/src/graphql/group-added.subscription.js

Changed client/src/graphql/group.query.js

Our other mutations will also look cleaner with their fancy input types as well:

Step 8.5: Add Input Types to Mutations

Changed client/src/graphql/create-message.mutation.js

Changed client/src/graphql/login.mutation.js

Changed client/src/graphql/signup.mutation.js

Finally, we need to update our React Native components to pass in the right values to the new input types. The changes are pretty trivial:

Step 8.6: Add Input Types to Screens

Changed client/src/screens/finalize-group.screen.js

Changed client/src/screens/messages.screen.js

Changed client/src/screens/signin.screen.js

Unlike with the previous tutorials in this series, this one doesn’t have a flashy ending. Everything should be working as if nothing ever happenend, but under the hood, we’ve vastly improved the way we make GraphQL requests to gracefully adapt to future changes to our Schema!

Fragments, default variables, and input types are essential tools for designing scalable GraphQL schemas to use in everchanging complex applications. They keep our code lean and adaptable. Apply liberally!

As always, please share your thoughts, questions, struggles, and breakthroughs below!

You can view the code for this tutorial here

--

--