The Best (GraphQL) API is One You Write

Avatar of Chris Coyier
Chris Coyier on (Updated on )

Listen, I am no GraphQL expert but I do enjoy working with it. The way it exposes data to me as a front-end developer is pretty cool. It’s like a menu of available data and I can ask for whatever I want. That’s a massive improvement over REST and highly empowering for me as a front-end developer who desires to craft components with whatever data I think is best for a UI without having to make slew of calls for data or ask a back-end developer to help make me a new bespoke API for my new needs.

But… who builds that menu of data? Somebody does.

If that somebody is a person or team at your own company because you’ve built out your own GraphQL API for your own needs, that’s great. Now you’ve got control over what goes in there (and when and how).

But sometimes GraphQL APIs are just handed to you. Perhaps that is how your CMS delivers its data. Still cool and useful, but that control is at the mercy of the CMS. You still have a menu of options, but the menu just is what it is. No substitutes, to continue the metaphor. If the menu doesn’t have what you need, you can’t go back into the kitchen and add extra sauerkraut to that reuben or have the steak fries come with fried mushrooms.

This came up in a discussion with Simen Skogsrud and Knut Melvær on an episode of ShopTalk. Their product, Sanity, is like cloud storage for JSON data, and a CMS if you need it. A modern product like this, you’d think a GraphQL API would be a no-brainer, and indeed, they have a beta for it.

But instead of GraphQL being the main first-class citizen way of querying for and mutating data, they have their own special language: GROQ. At first glance, I’m like: eeeeeesh, there’s a way to shoot yourself in the foot. Invent some special language that people have to learn that’s unique to your product instead of the emerging industry standard.

But Simen and Knut made a good point about some of the limitations of GraphQL in the context of a third-party handing you an API: you get what you get. Say a GraphQL API offers a way to retrieve authors. A generic API for that is probably designed something like this:

{
  allAuthors {
    author {
      name
      username
      avatar
    }
  }
}

But what I actually want is just how many authors we have on the site. Perhaps I wish I could do this:

{
  allAuthors {
    count
  }
}

But that’s not in the API I was given. Well, too bad. I guess I’ll have to request all the authors and count them myself. I might not control the API.

This means that something like a CMS that offers a GraphQL endpoint needs to make a choice. They are either very strict and you just get-what-you-get. Or, they offer not only a GraphQL API but a way to control and augment what goes into that API.

In Sanity’s case, rather than offer the later, they offer GROQ, which is a query language that is powerful enough you can get whatever you want out of the (JSON) data. And rather than making it this proprietary Sanity-only thing, they’ve open sourced it.

With GROQ, I don’t need any permission or alterations to the API to ask how many authors there are. I’d do something like…

{ "totalAuthors": count(*[_type == "author"]) }

(I actually have no idea if the above code is accurate, and of course, it depends on the JSON it is querying, but it’s just conceptual anyway.)

By giving someone a query language that is capable of selecting any possible data in the data store, it has a big benefit:

  • You can query for literally anything
  • You don’t need a middle layer of configuration

But it comes at a cost:

  • Complexity of syntax
  • No middle layer means less opportunity for connecting multiple APIs, exposing only certain data based on permissions, etc.