Add reactivity to an existing source using GraphQL Mesh

Jean-Yves Couët
Jean-Yves Couët

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. Unfortunately 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

2. Add graphql-mesh Packages

yarn add @graphql-mesh/cli @graphql-mesh/graphql @graphql-mesh/transform-resolvers-composition graphql

3. 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

4. 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 tuned ;)

@jycouet

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

Explore

Dive deeper into related topics.

GraphQL

Proven Schema Designs and Best Practices - Part 2

Jeff Dolle
GraphQL

Proven Schema Designs and Best Practices - Part 1

Jeff Dolle

Get your API game right.