Add reactivity to an existing source using GraphQL Mesh

This article was published on 2020-12-15 by Jean-Yves Couët @ The Guild Blog

Introduction

Working on the code generator for svelte plugin, I was looking for a public graphQL endpoint having queries, mutations and subscriptions for nice examples.
Unfortunatly I didn't find anything out of the box, ready to use for my demos. So I decided to extend an existing source!

Starting point

Across my researches I found one cool public endpoint regarding SpaceX. It has Queries and Mutations ready to use!
So I decided to pimp this endpoint, and bring a bit of reactivity with subscriptions.

The idea is to publish the new user when it's inserted with this mutation:

mutation addUser {
  insert_users(objects: { name: "jyc" }) {
    affected_rows
    returning {
      name
    }
  }
}

How hard is to do this? Let's find out...

Let's Pimp this graphQL!

Implementation

Multiple ways are possible!

Spoiler alert
Thanks to graphql-mesh, it's dead easy! 🚀🚀🚀

  1. Create a new repo
mkdir newRepo
cd newRepo
yarn init
  1. Add graphql-mesh packages
yarn add @graphql-mesh/cli @graphql-mesh/graphql @graphql-mesh/transform-resolvers-composition graphql
  1. Add .meshrc.yaml file in the root folder with
sources:
  - name: spacexGQL
    handler:
      graphql:
        endpoint: https://api.spacex.land/graphql/

additionalTypeDefs: |
  extend type Subscription {
    usersAdded: [users]
  }

transforms:
  - resolversComposition:
      - resolver: 'Mutation.insert_users'
        composer: ./src/composition/insert_user

additionalResolvers:
  - type: Subscription
    field: usersAdded
    pubsubTopic: usersAdded

Where I

  • declare the graphQL source
  • extend Subscription to listen to user added users
  • compose the existing Mutation.insert_users
  1. Add ./src/composition/insert_user.js file with all the logic for this new mutation composition.
module.exports = (next) => async (root, args, context, info) => {
  // add returning.id to the selection
  info.operation.selectionSet.selections[0].selectionSet.selections.push({
    kind: 'Field',
    name: {
      kind: 'Name',
      value: 'returning'
    },
    arguments: [],
    directives: [],
    selectionSet: {
      kind: 'SelectionSet',
      selections: [
        {
          kind: 'Field',
          name: {
            kind: 'Name',
            value: 'id'
          },
          arguments: [],
          directives: []
        }
      ]
    }
  })

  // send the mutation to the graphQL source
  const result = await next(root, args, context, info)

  // select returned ids
  const ids = result.returning.map((c) => c.id)

  // Query users enforcing fields to return
  const responseUser = await context.spacexGQL.apiQuery.users(
    {
      where: { id: { _in: ids } }
    },
    {
      fields: {
        id: true,
        name: true,
        rocket: true,
        timestamp: true,
        twitter: true
      }
    }
  )

  // publish new users
  context.pubsub.publish('usersAdded', responseUser)

  return result
}

That's it!

Wrap up

  • Extending an endpoint with subscription is easy! Thx to tooling.

  • You can find the source on github.

  • You see all this in action directly in the playground

I'm now ready to work on the demo for Svelte Codegen! Stay tunned ;)

Special thanks to n1ru4l who helped me finding the nicest way to do it ;)

55