Standard service - a fixed amount of work that is performed at a fixed price.  Post Service

  

Monday, 29 April 2019 15:04

GraphQL: REST in peace!

Written by  https://labs.cx.sap.com/2019/04/30/graphql-rest-in-peace/
Rate this item
(0 votes)

I agree, GraphQL is not exactly the new kid on the block. Dating back to 2012, developed at Facebook, it looks like we’ve missed quite some development. But

for those of you that know GraphQL, I guess we can agree that it just recently picked up a lot of traction… I am currently investigating GraphQL and would like to share my thinking with you – please comment or contact me via Twitter as I am really looking for a discussion!

This will be a multi-part series and this part is an Intro to GraphQL! Bookmark this page as I’ll be updating this post once new parts are out.

Update: The second part, a practical introduction (code!) to GraphQL Queries, Mutations and Subscriptions got published – have a look.

So what is GraphQL?

For a decade or so, the lingua franca of accessing APIs was via RESTful APIs – “whatever this may mean”. REST is a tiny bit complicated, as basically everybody agrees on parts of how it should work but there’s a ton of deviations that make it also really hard to use. The first requests typically work easily, but in the end you have to chain a lot of requests and you hit the server quite a few times for getting what you need. You essentially jump from entity to entity to get what you need – sometimes way more and there’s no way to stop the server from sending all that extra data.

GraphQL is quite different. First of all, GraphQL tries to “order” the data you can request in the form of a graph. Think of a product category – naturally you want to resolve the category, then the products and finally maybe the product images. GraphQL is a query language and execution engine, as the GraphQL specification tells us. In essence, all requests via clients are sent via POST requests, and these can either be queries, mutations or subscriptions. The requests sent must adhere to the schema that was previously defined. Interestingly, the clients send the requests (e.g. queries) to the server and the data returned is just the data requested – no extra fields here and there. This makes a whole lot of sense, as we’ve seen an explosion of different clients over the past years. Initially a lot of RESTful APIs were build to interface with 3rd party server systems. Then came mobile, and the same requests/responses were consumed via mobile devices and mobile connections. Finally, with IoT being in all our homes, a lot of these tiny devices still have to use the same RESTful APIs. And that makes REST look pretty old and crazily inflexible. It’s time for a change and GraphQL looks very promising.

So, is GraphQL for you? Are you tired of responses that hold way too much data? And sometimes not the data you need, so you need to make n+1 calls to get at it? Do you need to access many APIs from different systems? Do you do all this from tiny IoT or mobile clients? GraphQL is for you. GraphQL is for all modern clients out there – from single page web apps on your smartphone to IoT devices. 

A first example – the client perspective

Let’s break the ice by looking at a first example. We work from the client and issue some queries. Most GraphQL servers will automatically render a graphical UI to help developers get started with writing and developing queries – this UI is called GraphiQL – and I’ll use it to show you the first sample queries.

On the left, you see the issued query. The right side shows the response from the GraphQL server. Click the screenshot to enlarge. Notice how the query structure is mirrored by the response structure – and we got exactly what we asked for. We wanted to dive into the product category ‘brand_2’, get that categories name (‘Toshiba’) and the products’ id and name.

For these examples, I’ve used the node.js based yoga project. It’s an excellent choice to get started and uses the widely used Apollo GraphQL server underneath.

Now let’s say our client would like to show a list of products in a category view, so we need to get product images. Using the Commerce Cloud REST API, you would likely first resolve the category, then the products and images using a rather large request. Using GraphQL, we can issue a single request:

Here, we also used an input parameter to the images resolver to limit the images returned to format=thumbnail. This could be further extended to limit to a number of images, etc.

For the above examples, the responses from the RESTful APIs that are being called in the background via the GraphQL server are way larger. GraphQL shaped the responses and we just got what we asked for. Also, GraphQL saved us from making a couple of calls against the backend systems – in the worst case we would have to make these calls from a mobile client with bad network connectivity.

The server side: schemas and resolvers

Let’s now shift focus and switch to the server side. Here, as a developer of a GraphQL server, we need to think about the schema and resolvers.  The type system of GraphQL allows us to define a schema. The resolvers’ job is to execute queries and to resolve the data.

Here’s the schema that fit’s to the above example.

type Query { category(categoryId: String) : Category}type Category {  id: ID  name: String  subcategories: [Category]  products: [Product]}type Product { id: ID name: String description: String manufacturer: String price: String images(type: String, format: String): [Image] categories: [Category]}type Image { format: String type: String url: String}

All queries have the ‘query’ root type, in the next parts you will also discover mutations and subscriptions. Our resolvers will need to back this schema, e.g. provide functions for each of the Types and their fields. Let’s first take a look at the backing function for the query root type:

const rest = require('../rest.js')function category(parent, {categoryId}) { return rest.fetchCategory(categoryId); }module.exports = { category : category}

As you can see, the heavy lifting is outsourced to the rest.js library. Please assume that the fetchCategory call will make a request to our legacy REST API and resolve the category we submitted. Let’s also assume that the category response looks roughly like this:

{ id: 'brand_10', name: 'Toshiba'}

Do you spot the issue? While we would like to get products of a category, our legacy REST API cannot deal with that. To satisfy the response, it’s time to look into the resolver function for the Category type:

const rest = require('../rest.js')function products(parent) { return rest.fetchProductsByCategoryID(parent.id) }module.exports = { products: products}

When our root query resolved the category and our query is also asking for products, the Category’s ‘products’ resolver will be called. This is a really important part to understand. On a field level, we can create resolvers. This means, the call to fetchProductsByCategoryID will not be made, if the client query is not asking for it. But in this case, the client would like to get the products and therefore the products resolver of the Category type is called, now resolving the products. Ideally, our backend would not need to resolve the products in such a complicated and inefficient way – but that’s often the case with RESTful APIs.

If we now assume the products resolver would return products containing id, name, etc. but no images, you can imagine how we can extend this chain of calls. The resolvers kick in as they are needed to satisfy the incoming query and a single response can be rendered back to the client.

GraphQL: a no brainer for new APIs, extremely useful for legacy systems.

As we have to interface with so many different API clients with different needs today, GraphQL is a naturally good fit for all new systems. Each client gets exactly the data it has asked for – it fit’s perfectly to the API clients we can find in today’s landscape. This scenario is shown in the illustration below.

The second big scenario – and I believe currently even more relevant – is the legacy scenario. Here, we can use GraphQL as a server-side layer to combine and aggregate many different APIs and data sources. While we offer a nice Graph-like datamodel to the various clients (and yes, shaped API responses, too), we inconveniently need to resolve these queries via many differnt queries in the backend. We might need to get product data from this source and the product image data from another server. While this is inconvenient, we now shield the clients from this complexity. The various calls happen all in the backend where we typically have powerful servers and fast connections. Over time, we might be able to replace the one or other system transparently, too. This legacy scenario is shown in the picture below.

I hope you enjoyed this overview. Next up we’ll be taking a look at GraphQL Queries, Mutations and Subscriptions in greater detail. The final part of the series will deal with installing a client-facing GraphQL API within Kyma, an open-source project that can be used to to extend and customize enterprise applications such as the SAP C/4 Hana suite.

Read 155 times

Leave a comment

Make sure you enter all the required information, indicated by an asterisk (*). HTML code is not allowed.