Notes from GraphQL Contributor Days Nov'18

GraphQL Contributor Days is a community discussion hosted by ThisDot and Hasura. The first event was in November 2018; we invited folks from the GraphQL community in and around San Francisco, had lunch, discussed GraphQL, had coffee and discussed some more GraphQL. 🤓

The amazing folks at GraphQL contributor days - Nov 2018

This is a (long overdue) blog post summarizing the super insightful discussions that I was delighted to be a part of!

In attendance were:

And with all these awesome folks in the room together, these are the topics we discussed:

  • GraphQL & microservices
  • Error handling in GraphQL
  • GraphQL in production - authorization, caching, security
  • GraphQL on the client
  • GraphQL subscriptions
  • Sampling GraphQL and GraphQL onboarding in teams
  • Miscellaneous discussions

GraphQL and microservices

Does GraphQL make you think about your backend and microservices differently?

Nick kicked off the discussion by asking everyone what their microservices and the boundary definitions looked like, and how GraphQL was being incorporated.

These were the different approaches across the room:

  • Microservices: Almost automated GraphQL gateway with almost no “business logic” being used as a “Backend for frontend” (BFF) to upstream services that speak REST/GraphQL/gRPC

    • Pros:
      • GraphQL adoption was incremental and added instant value to client applications
    • Cons:
      • GraphQL API was not as client-driven as it could have been, and in some cases the “organisational” structure that was reflected in the microservices would leak into the client API
        • More “hops” could lead to increased operational complexity and less DRYness in the codebase.
  • Monolith (Facebook, Github): Native GraphQL API provided by the “business logic” service

    • Pros:
      • GraphQL API can be as client-driven as required
    • Cons:
      • Requires significant buy-in of “backend” team and working with existing code
  • Hybrid approaches:

    • Approach 1: Product infrastructure / platform team composed of backend, infra, frontend developers implement a GraphQL gateway.
      • Per Sasha, this is a successful approach for Medium even as the monolith is being broken into microservices (that speak via protobuf). The GraphQL gateway does some level of data transformations, error-handling to make the API is client friendly, but does not implement any other business logic.
    • Approach 2: Start by building a GraphQL gateway to REST services to provide immediate value to client teams, but gradually merge with the REST service.
      • In Uri’s work with enterprise clients with large amounts of legacy code, this approach seemed to be feasible and the GraphQL service was planning to eat the REST service. Incidentally the REST service in this case was proxying to SOAP endpoints, so it made an unusual amount of sense to merge the GraphQL and REST service. Uri mentioned that they also try to move things towards a monorepo (Nick’s face lit up like anything) to improve automation and workflow.

Nick expressed 2 key concerns that could crop up if GraphQL support is not added "natively":

  • If you split up the microservices by organizational domains (Conway’s law) and structure your GraphQL schema by putting them together, then you are leaking your organizational structure to the client.
  • While building a GraphQL gateway atop existing microservices, you are adding a new component, thus potentially introducing new process and performance overheads

Error handling in GraphQL

TL;DR: Go watch Sasha’s talk: https://www.youtube.com/watch?v=GYBhHUGR1ZY

As far as possible, model errors in the type system. Union types are especially handy. This works for “application” errors which are expected states that your application and user could find themselves in. However before everyone migrates to union types, Jon issued a fair warning: union types are a breaking change for the client and should be rolled out thoughtfully!

(Other types of errors are transient errors in the system or system level errors where the application is in an unknown state. These are hard to model in the application type system.)

Hot takes:

Kyle: Most errors are just another “state” in your application.

Nick: If there are 3 things we would change about GraphQL when we launched it:

  1. Called GraphQL mutations “GraphQL actions”
  2. GraphQL would have had a built-in story for streaming data
  3. Errors. Error handling was half-baked at the outset

GraphQL in production

I asked for a quick round-up of practices and methods around authorization, security, performance, caching and here’s a quick rundown of what different teams were up to.

Authorization:

  • Most common approach: Authorization done as usual by the upstream service with null returned for fields that are inaccessible
  • Input provided to GraphQL resolvers (in some cases via schema directives to make it easy to review the schema) to enforce authorization in the resolver

Security:

  • Mark: Depth check and reject, with a gradual move to weightages planned.
  • Jon: Long running queries trigger a latency alarm

Performance/caching:

  • Jon: We enforced “multi-GET” on the upstream REST APIs to make fetching from the upstream services faster for the GraphQL gateway
  • Sasha: Observed that overall latency increased for some GraphQL queries because of introduce another hop with the GraphQL service that calls upstream services.
  • Conor’s performance tip on the client-side: Please don’t create the GraphQL query string in the `render` function of your react apps. It gets rebuilt a million times and is a performance gotcha commonly seen with folks writing their first GraphQL apps!
  • Brian: Use the graphql batch ruby gem.

Caching:

  • Jon: No server-side caching yet, but this could be a HUGE win for the team
  • Garett: Caching is also problematic when there is PII data so it’s not easy to enable “globally”
  • Eran: We do in-memory caching on the GraphQL server to cache resolver results
  • Tyler: HTTP GET caching works well, because Tyler has GraphQL On The Client™️

One of the key open questions that emerged was around improving sequential information access from the GraphQL service to upstream services? Can we fetch information parallely by improving query-resolver traversal?

GraphQL on the client

Client-side state: Redux vs apollo-link-state:

In most cases, for those using Apollo, most state that was being handled was remote state. In those cases where there was client-side state it is usually handled locally in the react component’s state object. In case components need to share client-side state, the most common solution has been to create a parent component that manages the state and passes it down to children via props.

  • Shruti mentioned that because apollo-link-state was painful to configure, they abandoned it in favour of react local state and it’s been possible to get away with that.
  • Sasha: We currently use redux for queuing up “toasts” on the app, however it would seem that most things can be achieved with apollo-link-state.

Redux middleware was awesome

  • Uri reminded everyone that one of the most powerful and amazing things about redux was the ability to add your own middleware (some nostalgic nodding was observed). However, because apollo-link is “below” the cache, it’s not easy to write a middleware type utility with apollo-link. Uri and team recently open-sourced Loona.js. It is a client library that wraps over apollo-client and apollo-link-state to bring back the easy flexibility that redux middleware offered. Loona allows the developer to define “effects” which can be attached to a set of “actions”. Read more about it here and in the docs.

Relay

Although relay use was not very common (Eran mentioned that they’ve been on Relay for a while), mostly because Relay seems to be very opinionated, Relay did have some interesting ideas. Uri mentioned that it would be great to explore how to bring those ideas to other clients like Apollo, or how to make Relay more flexible.

  1. By enforcing opinions on the GraphQL schema, Relay can automatically handle the cache, busting it and updating it as mutations happen.
  2. Relay can extract GraphQL documents from across a codebase, transform/optimize them, and generate build artifacts. After getting the basic client working, devs like having a statically analysable set of GraphQL queries that a client makes anyway, and Relay makes this happen this out-of-the-box. Use-cases include persisting optimized GraphQL on the server, runtime representations of the queries for clients like the Relay runtime, or generated source code for use with compiled languages (Java/Swift/etc).

Hot takes:

  • Jon: Look at BabelBlade to reduce double-declaration. The GraphQL query is “inferred” from the resulting data object being used in the react code!
  • Eran/Syrus: What if we had a universal GraphQL client with webassembly! 😲

GraphQL subscriptions

GraphQL subscriptions are still not commonly used, per the sample in the room. However, there are many interesting ideas around live queries to ease client-side work. The @live and @defer tags are especially exciting in this regard, albeit need more client-side support.

Jon had an interesting take where it might be possible to implement @live and @defer directly on the client without needing server-side buy in. Fields marked with @live would undergo a polling. Fields marked as @defer, which are potentially slower GraphQL queries, could be queried after the main query was run.

Sampling GraphQL & GraphQL onboarding for teams

Brian kickstarted the conversation by describing his initial steps with getting used to GraphQL when starting out at Github, and asking what kinds of things could be done to make the onboarding for new developers to the team’s GraphQL stack better.

The room then discussed different approaches to GraphQL onboarding:

  • Jon: On the frontend side, build a basic UI component with the GraphQL API. On the backend side, especially to get familiar with GraphQL schema designing, fill in a “hole” in the existing GraphQL schema.
  • Uri: Getting familiar with the GraphQL API using GraphiQL and GraphQL voyager to visualise the API
  • Sasha: Series of mini onboarding courses. From things like the React/GraphQL architecture and making queries from the app to improving GraphQL query performance and making additions to the schema.
  • Mark: Start by pointing people to the docs and then do a mini-workshop for the client-side and the server-side.

Open discussion

Jon posed the question to the room of what the new tools and resources that we need to build in the current ecosystem would look like.

  • Garret: Improving tooling around query planning
  • Tanmai: Better content and tooling around implementing performant GraphQL queries with existing popular language/framework ORMs
  • Uri: Better vendor agnostic tutorials
  • Better linting: Lint rules for unused query fields, pre-processors for IDE typeaheads and build-time setups, making eslint handle “async” processing

Hasura is an open-source engine that gives you realtime GraphQL APIs on new or existing Postgres databases, with built-in support for stitching custom GraphQL APIs and triggering webhooks on database changes.


PS: We’re hiring!


Tanmai Gopal

Tanmai Gopal

Tanmai is the co-founder of hasura.io. He is passionate about making it easier to build things.

Read More