My First GraphQL Java Client (and why it’s worth a blog post)
Natasha Chernyavsky, Wed Oct 14 2020, 7 min

Introduction

Working as long as we had in a Java-based, µ-service architectured ecosystem, we were used to having our main communication channel being REST APIs (that is, when we were not using Pub/Sub patterns). 
We felt like we had it all figured out. Service A wants some data that Service B is managing? No problem! Add a REST client to Service A and connect it to Service B. If combining several resources is required, perform several queries and merge the data on Service A. Today you even have excellent Java libraries like Spring Cloud Feign to save you from writing boilerplate code. EASY.
It was no wonder then, that when we were required to connect to an external Shopify API, we took to the task with a smug state of mind. JUST ANOTHER API, right? 
Well, not exactly. Shopify’s API implementation uses GraphQL, a query language created by Facebook to overcome the shortcomings of the REST structure (like hierarchical data structures, data selection, etc). This seemingly small detail led us on a journey that included writing our first GraphQL Java client, which was definitely not “just another API client.” 
In this post, I’ll explain why using the same Feign client to query data was not an option, I’ll discuss which existing Java libraries are available, and finally, I’ll describe an intermediate solution we implemented using a simple RestTemplate and Server-side templating. 

The Hubris: “GraphQL? It’s just another API”

Oribi’s architecture consists (mainly) of Java µ-services (using Spring Boot and Maven as a Build tool), the main communication method between them is REST APIs and our library of choice is Feign. Working on our eCommerce solution for Shopify, we had to connect to Shopify’s GraphQL API. We set to work thinking “Ok, it’s true that we have never worked with GraphQL, but come on! It’s still an API...it’ll probably just involve creating ANOTHER client, some endpoints and then we’ll be done with it.”
Pretty quickly we understood that using our good old Feign client would not work. While REST specifies that queries should use the GET verb (usually passing arguments and parameters to describe the query), and POST/PUT/DELETE for mutations (utilizing the request’s body to describe the changes—usually in a JSON structure), GraphQL’s queries and mutations are a bit more complex and special interpretation is needed.
For example here is a sample query that requests shops’ resources along with the first order made in that shop.
query { 
   shop { 
      id 
      name 
      email 
   } 
   orders(first:1) { 
      edges { 
         node { 
            id 
         } 
      } 
   } 
}
to which the response would be the following JSON:
{
    "data": {
        "shop": {
            "id": "gid://shopify/Shop/1234567",
            "name": "My Favorite Shop",
            "email": "sara@myfavoriteshop.com"
        },
        "orders": {
            "edges": [
                {
                    "node": {
                        "id": "gid://shopify/Order/1234567890"
                    }
                }
            ]
        }
    }
}
It’s easy to notice that the query’s structure is not a simple JSON object, but rather more like a combination of JSON and a functional language.
We kind of hoped that the Feign library would support GraphQL, but unfortunately it did not. And so, without a specific encoding/decoding solution from Feign, we were unable to use it.

The failed hope: "Surely other libraries will work. Right?"

Even though we were GraphQL newbies, we quickly pulled ourselves together and did what any group of self-respecting engineers would do, which was to search the web for a similar-to-Feign solution we could simply integrate and use. 
The web is filled with information about how to build a Java GraphQL API to serve data, and while it certainly includes a learning curve, it can be done pretty easily with Java Spring Boot (there are a lot of boilerplate Maven dependencies in existence such as graphql-spring-boot for example). However, finding resources on how to build a Java client for a GraphQL API turned out to be, well, unexpectedly hard. 
GraphQL.org has a nice reference that lists libraries in different languages, both for Server and Client. For Java, it contains the following:
  1. Apollo-Android (around 2.5K stars on GitHub)
  2. Nodes (around 300 stars).
Turning to the more widely used library, we started checking out Apollo-Android, which was created mainly for Android but can be used with Java/Kotlin. The documentation for the project is quite friendly, and if you are using the Gradle build tool for your services, you can easily (I can only imagine) import it and start using it. However, if you are using Maven (like us here at Oribi), you encounter your next roadblock, since Apollo-Android does not have a Maven plugin.
A few more hours of searching followed, then some trial runs of various low-starred Maven-supported repositories, all of which resulted in nothing. And this was all accompanied by major self-doubt, both of my understanding of GraphQL, as well as of my engineering troubleshooting abilities.

The solution: going back to the basics

At this point, since we were required to connect to a third-party API and use only a small subset of the available queries and mutations, the need for speed became paramount. 
Instead of migrating our code to use the Gradle build tool, we decided to settle for an intermediate solution using a simple RestTemplate, whereby we performed an HTTP POST request with the GraphQL query contained in a string in the request’s body:
POST <GraphQL root url> --header 'Content-Type: application/json' --data-raw '{ "query" : "query { shop { id name email } orders(first:1) { edges { node { id } } } }" }'
In addition to the RestTemplate, we used Mustache Server-side templates (using spring-boot-starter-mustache as a dependency). The gist was to create template files for the required queries/mutations, compile them with the parameters for the query, and then send them as a regular POST request using RestTemplate.
As an example, I’ll show an implementation for fetching a subscription object resource by its id from the Shopify GraphQL API.
The GraphQL query looks something like this (this is a variation of course, you can include more or fewer fields to retrieve):
query {
  node(id: "gid://shopify/AppSubscription/<SUBSCRIPTION ID HERE>") {
    ...on AppSubscription {
      createdAt
      currentPeriodEnd
      id
      name
      status
      test
    }
  }
}
We created a get-subscription-by-id file containing the appropriate template:
query {
  node(id: "gid://shopify/AppSubscription/{{id}}") {
    ...on AppSubscription {
      createdAt
      currentPeriodEnd
      id
      name
      status
      test
    }
  }
}
In addition, we created a class called ShopifyGraphQLRequestDTO, which holds the query as a string:
public class ShopifyGraphQLRequestDTO {
    private String query;
}
And here is the actual code for querying:
import com.samskivert.mustache.Mustache;
import org.springframework.web.client.RestTemplate;

public class ShopifyBillingGraphQLClient {
    private final RestTemplate restTemplate;
    private final Mustache.Compiler mustacheCompiler;

    public ShopifyAppSubscription getAppSubscriptionByChargeId(String chargeId) throws UnsupportedEncodingException {
        HttpEntity<ShopifyGraphQLRequestDTO> entity = this.getRequestHttpEntity(GET_RECURRING_CHARGE_TMPL, ImmutableMap.of("id", chargeId));
        String graphQLRoot = ‘<SHOPIFY GRAPHQL ROOT URL HERE >’;
        ShopifyAppSubscriptionQueryResponseDTO response = restTemplate.postForObject(graphQLRoot, entity, ShopifyAppSubscriptionQueryResponseDTO.class);
        if (Objects.isNull(response.getData())) {
            log.error("1 or more errors occurred while creating app subscription: {}", response.getErrors());
            throw new UnexpectedBillingException(Joiner.on(',').join(response.getErrors()));
        }
        return response.getData().getAppSubscription();
    }

    private HttpEntity<ShopifyGraphQLRequestDTO> getRequestHttpEntity(String requestTmpl, Map<String, Object> params) throws UnsupportedEncodingException {
        String requestBody = this.getQueryBody(requestTmpl, params);
        ShopifyGraphQLRequestDTO requestDTO = ShopifyGraphQLRequestDTO.builder().query(requestBody).build();
        HttpHeaders headers = new HttpHeaders();
        // can set the content Type
        headers.setContentType(MediaType.APPLICATION_JSON);
        return new HttpEntity<>(requestDTO, headers);
    }

    private String getQueryBody(String templateName, Map params) throws UnsupportedEncodingException {
        return mustacheCompiler
            .compile(this.getTemplate(templateName))
            .execute(params);
    }
}
Of course, you have to create the appropriate POJO classes for the response objects such as ShopifyAppSubscriptionQueryResponseDTO above.
And that’s it! You’re all done! 

Should you simply use this method for future GraphQL clients?

While this method is pretty straightforward, it does take us back to the RestTemplate days and reminds us how tedious it can be to work with complex APIs containing a lot of queries and mutations. This was a quick solution for us that did not require much, but ideally, we would like to use a Feign-like library, which would save us from writing boilerplate code. Also, the example I gave is pretty simple, but as you move to queries that require pagination, etc., the plot thickens. 

A retrospective and next steps

I was surprised to learn that GraphQL client Java libraries were scarcely available and even as I’m writing these lines, I’m still not sure if I missed something during my search for one. GraphQL was created by Facebook with mobile and web clients in mind (the first published implementation of GraphQL was in JavaScript), but because it provides a query language for complex and hierarchically structured data, one can easily wish to use it for exactly such scenarios, even with server-side APIs, and for communicating between µ-services. And the engineers with such needs are still heavily using Java. 
A deeper inspection of Apollo-Android is definitely a good idea and would be a next-step if you wish to start using GraphQL APIs more in your system (both implementing and querying it).
I hope this post will help you get started and that it identified some obstacles you may encounter if you are, like us, used to working with REST APIs. 
We’re Hiring!
Oribi is growing,
come join our amazing team :)
Check out our Careers Page