Incremental Graphql

Quick refresher

  • query language for APIs 
  • alternative to REST
  • customizable requests

Why Graphql?

  • One centralized endpoint
  • Client gets exactly what it needs
    • less overhead
    • faster
  • Typed!

This all sounds great but what about when you have tons of legacy code that uses REST

Easy APIs

  • You can use tools like Prisma or Hasura to autogenerate a schema from your database models
  • Hasura, for example, "auto-generates queries as part of the GraphQL schema from your Postgres schema model. It generates a range of possible queries and operators that also work with relationships defined in your SQL schema".

Mock Data

  • You can mock the data that is returned from your API to get a quicker start
  • As easy as setting mocks to true when you start your Apollo Server
  • Or you can customize your mocks
const { ApolloServer, gql } = require("apollo-server");
const faker = require("faker");

const typeDefs = gql`
  type Dog {
    id: ID!
    name: String!
    age: Int
  }
  type Query {
    allDog: [Dog!]!
  }
`;

const mocks = {
  ID: () => faker.random.uuid(),
  Int: () => faker.random.number({ min: 1, max: 25 }),
  String: () => faker.name.firstName(),
};

const resolvers = {
  Query: {
    allDogs: () => [{id: 1, name: "Meatball"}]
  }
};

const server = new ApolloServer({typeDefs, resolvers, mocks, mockEntireSchema: false});

server
  .listen()
  .then(({ port }) => console.log(`Server running on port ${port}`));

Baby steps on the client

  • You can use a regular fetch/axios/graphql-request
  • Note that these will be POST requests with the query as the body
var query = `{ allBooks { title } }`;
var url = "https://books.com/graphql";

var opts = {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ query })
};

fetch(url, opts)
  .then(res => res.json())
  .then(
    ({ data }) => `
        <p>Book of the day: ${data.Book.title}</p>
  `
  )
  .then(text => (document.body.innerHTML = text))
  .catch(console.error);
import { request } from 'graphql-request'
var url = 'https://books.com/graphql'

var mutation = `
    mutation newBook($title: String! $author: String!) {
        addBook(title: $title, author: $author) {
            title
            author
        }
    }
`

var variables = { title: 'Jane Eyre', author: 'Charlotte Brontë' }

request(url, mutation, variables)
  .then(console.log)
  .catch(console.error)

Case study: Twitch

  • They built graphql on top of a REST backend at first, and then rebuilt the services with graphql instead of REST
  • "Adding a GraphQL API to the ecosystem was like adding a missing unit test”
  • Went from 0 to 100% graphql in a year
  • Tens of REST requests -> single GraphQL request
  1. Start with a prototype schema
  2. Built out types for logged-out version our the front page (authentication is tough...)
  3. Client-driven approach to figure out what data to get from the GraphQL API
  4. Incorporated pagination with help from Relay's pagination specification
    • standardized, consistent scheme
    • allowed services to adopt cursor-based pagination on their own time
  5. Moved auth logic into services (and out of API layer)

Further reading

Incremental Graphql

By borisonr

Incremental Graphql

  • 567