Hacker News new | ask | show | jobs
by waffleau 1743 days ago
I didn't choose to adopt GraphQL, but I joined a company where an ex-developer had integrated into what was at that point a core codebase. They didn't add it due to any particular merit, they just wanted to play with shiny new technology. The codebase also had REST endpoints, but GraphQL made up the majority of the API, so we decided to just run with it and deprecate REST. At the time the decision we made was arbitrary.

This turned out in retrospect to be a good call. The primary consumers of the API were a set of Android and iOS apps, and integrating GraphQL into mobile apps is a pleasant experience. You can generate your data models from the graph schema. Tools like GraphiQL allow developers to explore and play with your API, substantially reducing the amount of documentation needed. The mobile team much preferred working with GraphQL over REST.

On the backend, GraphQL has a bit of a learning curve. The resolver pattern is powerful once you understand how to use it properly, but also easy to misuse. The most common source of problems is developers not understanding Graph's batch resolution mechanism. Developers accustomed to building REST APIs rely on preloading data, which is the wrong approach when dealing with GraphQL.

As a simple example, maybe you initially build a Graph query where you load comments like this:

  query Comments {
    user {
      posts {
        comments {
          message
        }
      }
    }
  }
But later on, you decide you want to allow a user to load their comment history directly:

  query Comments {
    user {
      comments {
        message
      }
    }
  }

In the first example, an equivalent REST API might load comments via something like posts.preload(:comments), and when the second query is built you'd use user.preload(:comments). But the way to solve this problem in Graph is batch resolution - get a list of comment IDs you want to load, then call Comment.where(id: comments_ids). Your comment loading is now context agnostic.

Another related problem is that it is easy to create N+1 queries. This also stems from a misunderstanding of batch resolution - reusing the above example it would be the equivalent of calling Comment.find(comment_id) for each ID instead of Comment.where(id: comments_ids). My first few months working with Graph were often spent fixing N+1 queries. As much as I try to explain this problem to new developers, it's one of those things that doesn't click for them until they cause the problem and end up having to fix it.

Once you understand GraphQL it's a nice technology to work with. In the early stages it can be fairly easy to shoot yourself in the foot, you just need to build up enough knowledge to avoid the common pitfalls. In general, GraphQL APIs are harder to build than REST APIs (mostly because REST is the default for most frameworks). If I had to start a new project today, my decision on whether to use GraphQL would be be determined by questions such as:

  1. How much control do I have over the clients
  2. Are the primary consumers native mobile applications 
  3. Is flexibility important
  4. Will API documentation be required
1 comments

Good stuff.

I'm surprised about the native mobile thing; is working with REST that arduous on mobile? I come from a web background so I don't really know

It definitely requires more work. If you're starting from scratch, you need to either read the API documentation or makes calls to the API to understand the data you're getting back. You then need to build correctly typed data models that match what you're expecting the API to give you. There's plenty of room to make mistakes as it's a manual process.

With GraphQL you can take the schema file from the server and use it to generate your data models. You get the data models for free, everything is correctly typed, and as long as the schema you're using is up to date you have a guarantee on correctness. It also makes finding changes to the schema easier in the future, as you can effectively do a diff.

We also use GraphQL on web (the exact same API as mobile) but we don't realise nearly as many of these benefits. This is probably in part because we haven't invested a lot in tooling, but also the team that maintains the API also maintains the web product, so some of the discoverability benefits of Graph aren't as valuable.