1. 程式人生 > >GraphQL: The hero we deserve (Part 1)

GraphQL: The hero we deserve (Part 1)

The motivation

Have you ever been frustrated with using REST APIs for supporting multiple clients types both mobile and desktop ? I sure have been. Things move so quickly these days on the client side, with incoming product requirements and customer feedback, that managing both UI and API updates become a nightmare. You may have to add mobile-specific fields to your API, which the Desktop clients don’t really need, or worse, you end up creating different versions for different clients and have to evolve them individually. Oh gosh, the pain ? ?!

Why REST is a thing of the past?

Don’t get me wrong though, I’ve used REST for quite some time and it’s great for what it allows for. You can have stateless server implementations which structured access to resources. It’s very quick to spin up a RESTful API in a matter of minutes and is supported by frameworks across all the major programming languages. But as you know —

“With great powers, comes great headaches”.

REST as a spec is widely misunderstood and everyone company out there has its own flavor of it. The clients become tightly coupled with their back-ends and thus become difficult to iterate over. Resource access through convoluted specs like HAL and HATEOS is just a pain in the ass, and difficult to maintain. And finally, under-fetching and over-fetching ( more on these in the sections below ) is a real issue, keeping in mind empathy towards your end user’s data usage and overall experience in mind.

What is GraphQL?

GraphQL is an open-source API spec, born out of Facebook, which provides a more efficient, powerful and flexible alternative to REST. Keep a note that, GraphQL is just a spec, Facebook and a large community of open-source contributors maintain many of the popular GraphQL client and server implementations. For a full list of free resource check this repo out.

Let us take a very simple example to understand the difference between a typical REST and a GraphQL API. Consider you’re making a “Tinder” clone and you have a page where you need to show the following things —

Sample client mobile page
  1. Current logged-in user’s name
  2. People who right-swiped the user.
  3. Last 3 people whom the user right-swiped.

A typical RESTful implementation for this would have endpoints as below —

  1. /api/user/<id>
  2. /api/user/<id>/likes-received
  3. /api/user/<id>/right-swipes

Each of the above endpoints would return a JSON payload containing data for different parts of our page. The JSON payloads may take a shape like below —

1.) /api/user/<id>

{  "name": "Peter Parker",  "age": 25,  "email": "[email protected]",  "phone": "xx-xxxx-xxx",  "billing": ...}

2.) /api/user/<id>likes-received

{  "count": 4,  "users": [{     "name": "Norman Osborn",     "age": 40,     "email": ...    },{      "name": "JJJ",     "age": 45,     "email": ...  }, ...  ]}

3.) /api/user/<id>/right-swipes

{ "users": [{     "name": "Mary Jane",     "age": 25,     "email": ...    },{      "name": "Gwen Stacy",     "age": 23,     "email": ...  }, ...  ]
}

Now observe closely! Do you notice anything here? To a REST veteran this seems totally fine. But pay more attention and you’ll see that the APIs return more data than we’re actually showing on the client. The fields like “age”, “email”, etc. are redundant for this particular screen and thus results in a wastage of user’s precious bandwidth. This is a typical case of “Over-fetching”. Also as you can see that this is profile page and it requires 3 API calls to render it. This means that our ‘/user ‘ API endpoint is insufficient to get all the data to show a user’s profile page, and thus it “Under-fetches”.

Also,it is evident that the UI is tightly coupled with the APIs and any change in the page will require corresponding API changes. This slows down product iterations, as more cross-cutting changes ( and concerns ) are required.

A GraphQL version of the same product has just a single endpoint and uses a declarative GraphQL query to get all the data the page needs in a single shot. A sample query and JSON result is as below —

// QUERY ?
query{
  User(id: "my_id"){     name    likes-received{      name    }    right-swipes(last: 5){      name    }}
// RESULT (JSON) ?
{
"data":{    "User": {   "name": "Peter Parker",      "likes-received":[     {"name": "Norman Osborn"},      {"name": "JJJ"},      ...    ],
   "right-swipes":[    {"name": "Mary Jane"},     {"name": "Gwen Stacy"},     ...   ] }} 

As you can see this is much more terser and declarative way of fetching data. The query is very self-explanatory and anyone reading it would immediately get what the response structure would look like. We’ve finally gotten rid of the evil of under and over fetching data. What a relief! ?

For a more visual representation of what’s going on, feast yourself with the diagram below.

REST vs GraphQL APIs

And now finally, Peter can be cool and go out —

That’s all good. What else?

Well! If you liked the story till now, wait till you read the points below. They’ll definitely knock your socks off. ? ?

  1. Get rid of over and under fetching data⚡️ — As discussed above, over and under fetching are the tow evils of REST world which eat away your user’s data plan as well as hinder their experience. GraphQL by design allows you to get rid of them for good.
  2. Awesome Schema and Type system — GraphQL comes with an SDL ( Schema Definition Language ) which allows you to design your data models with great ease. Also, the SDL has a very strong type system, thus you can have static type checking for your schema. Compare this to the REST’s JSON world where you don’t have any kind of schema or type checks. Real Bummer right ?!
  3. Better API versioning — In the REST world, whenever there’s a new requirement which requires a breaking change in the current API, we just create a new version of the API. We’ve all seen version hell ( v1, v2, v3, v-final,… ). But GraphQL takes a whole different approach to API versioning, with not supporting versioning at all. Yeah you heard it right! Since GraphQL only returns the data that’s explicitly requested, so new capabilities can be added via new types and new fields on those types without creating a breaking change.
  4. Improved API insights? — Since the client is the king here, over time we can monitor what data our clients are actually querying for and deprecate the fields not in use anymore. Also in GraphQL, every type has its own resolver function. This allows for low-level monitoring and optimization of any bottleneck in these functions.
  5. Easy Pagination ? — You may want to return long lists from your APIs and then paginate them as per the client needs. GraphQL is well equipped for this scenario with query specifiers such as ‘first’ and ‘after’.
  6. Schema stitching/composition — GraphQL allows you to compose schema, which may fetch data from different sources, and allow you to serve and query the data with a sing endpoint and root query. More on this later.
  7. Great OSS community ?— It goes without saying that GraphQL is a community-driven project. There are a lot of smart people building server and client implementation in several languages. The community is thriving and you can find almost any help you might want. So just get out there and see for yourself.

If this intrigued your imagination ?, head toPart 2of this post and learn about the core concepts of GraphQL — Schema, Query, Mutations, and Subscription.