Skip to Content

Overview

When being involved in discussion of microservices and lightweight APIs design and development, in clear majority of cases, I find such discussions are primarily centered around REST architecture style. Interestingly, participation in such discussions commonly leads me to observation of relatively broad interpretation of what canonical RESTful API shall look like. Although there are certain principles that are defined and promoted by REST, we shall acknowledge the fact that REST is a set of guiding principles, rather than a specific defined standard or protocol.

As a result, there have been few protocols that were developed following REST principles – among them, OData proved itself to be probably one of the most popular in the area of designing and implementing APIs for data querying. OData is clear, lightweight and relatively simple to understand and use – being commonly referred as “SQL for the Web”, OData is capable of provisioning native API-level representation of queried entity types and mirrors logical data model used by the application to certain extent. Complexity is introduced when it comes to composition of complex requests that need to query several entity types and execute nested queries. To avoid superfluous complexity, one of commonly faced approaches is based on exposure of entity type specific OData services that limit nested queries to some sensible level. This approach has direct impact on number of service calls and related data processing and merging, that have to be made by client application on the way of retrieval of all required data – not only this brings extra complexity to client application’s logic, but might cause performance degradation.

To address this issue, Facebook developed yet another data query language – GraphQL – that was originally developed in 2012 and used for internal needs in the area of native mobile applications development. Following success caused by flexibility and light footprint of the query engine, GraphQL evolved and was released and made publicly available in 2015.

GraphQL provides server application with convenient means of description of exposed entity types (object types) and their relationships, and client application – with tooling required to query data by requesting specific fields of object types, including querying linked types and retrieving their fields, applying filters, etc. in JSON-like format. Response to an executed query comes in JSON format. Although it might look familiar to OData, it is very different in the way how query is composed by client and query handling is implemented by server. Details on GraphQL query language, concepts employed by it and examples can be found at http://graphql.org/. Intention of this blog is not to make deep dive into them, but to demonstrate how they can be applied in practice and how the application that exposes GraphQL API can be implemented and deployed to the cloud platform.

 

Server-side demo application: description and remarks

In sake of demonstration, I make use of Java Spring Boot framework for which GraphQL provides corresponding Spring Boot Starter, and develop Spring Boot application that exposes data using GraphQL.

The application is going to be deployed to Cloud Foundry environment of SCP, and will make use of MongoDB service instance that has been created and started in the same Cloud Foundry space. Generally speaking, GraphQL is persistence layer agnostic and can be effectively used in conjunction with variety of persistence layer technologies and products, and even enable development of the API that retrieves data from different data sources. As it will be seen from the example, GraphQL tooling, being combined with Spring, provides required level of abstraction from specific technology used on persistence layer level.

Another important note is about the way how the developed application interacts with MongoDB service – to query data from MongoDB, I make use of corresponding Spring Cloud Connectors for Cloud Foundry. Concept of Spring Cloud Connectors is based on the idea of provisioning of mechanism and components that are based on it, and that enable smooth interaction with various cloud platforms’ using unified principles and patterns. There are already a lot of connectors that fulfil needs of application integration with some services provided by cloud platforms, as well as custom connectors can be developed, should they be needed and not yet available from vendors. SAP team has also heavily invested into this mechanism and provides connectors for certain services (such as HANA) available for both Cloud Foundry and Neo environments of SCP. Should you want to learn more about this concept, please check Spring Cloud Connectors’ official documentation. To get more information on SAP’s contribution and Spring Cloud Connectors for SCP, pay special attention to blogs written by Matthias Steiner, where he shares information on connectors developed and brought to community by SAP (https://blogs.sap.com/2014/12/12/released-spring-cloud-connectors-for-hcp/ and https://blogs.sap.com/2014/12/19/enterprise-granny-part-11-one-for-all/).

Overview of main components of the developed application and tools that will be used for querying exposed GraphQL API, is provided on the illustration below:

The developed application’s GraphQL API will only expose a single query type and will not allow other CRUD operations (no mutations), but this will already provide good illustration on how the entire concept works and how it can be applied.

Data model used within the application, is based on sample music library database example, that, in sake of simplicity, contains such object types as ‘Artist’, ‘Album’ and ‘Track’ with few attributes each. To demonstrate querying capabilities, we need at least two inter-related object types, so that retrieval of data for multiple entities of different object types by means of a single query execution can be illustrated. Data model representation is provided on the illustration below:

 

Development of involved Spring Boot application has been carried in Eclipse IDE extended with Spring related plugins, dependencies management and build has been conducted using Gradle. Application’s source code, configuration properties and Gradle build script can be found in GitHub repository.

 

Server-side demo application: implementation

To embed GraphQL runtime engine in the developed application, following dependencies should be added:

  • Artifact ID ‘graphql-spring-boot-starter’ of group ID ‘com.graphql-java’,
  • Artifact ID ‘graphql-java-tools’ of group ID ‘com.graphql-java’.

 

Schema

First of all, the application needs to manifest the API contract that can be used further on server-side when implementing application logic, as well as by client when querying GraphQL API. This contract is composed on basis of provided GraphQL schemas that contain definition of types (object types, queries, mutations, etc.) and that can be queried via future developed API, as well as relationships between them, where applicable. Convenient way of defining schemas is through their externalization and placement in dedicated files with ‘.graphqls’ extension. In the demo, as data model is fairly simple, all required types are located in a single schema life – in real life examples, good practice is to split type definitions and spread them across multiple schema files, so that logically related types can be grouped in the same schema file, and each schema file is not overloaded and overcomplicated.

As it can be seen from the schema file declaration, it defines used object types and query. In the example, album object type, when queried, can be enriched with information from referenced artist and track object types.

 

Types

As noted from the above, three object types – ‘Artist’, ‘Album’ and ‘Track’ – have been defined in GraphQL schema. Entities for these types are going to be persisted in corresponding collections in the MongoDB database instance, for which the developed application has binding. For each of the used object type, respective so-called data class (or entity type definition class) should be created – such classes are Java representation of persisted object types, hence, they shall declare all corresponding object type fields / attributes. Since MongoDB is used as persistence layer, it is convenient to annotate such classes with annotation ‘@Document’.

 

Field resolvers

After types and corresponding data classes are defined, next step is to implement relationships between them, following those defined in GraphQL schema. In terms of GraphQL, this is all about implementing so-called field resolvers – methods that are responsible for retrieving required entity in response to query when it is referred from the other entity.

Here comes an important note: field resolver function is executed on demand – it is not executed unless corresponding object type is queried. Such approach is performance friendly, especially when dealing with complex queries execution, when field resolvers might need to be invoked many times (for an array of entities) or implement long-running data retrieval logic (complex logic, time consuming data retrieval from external persistence layers, invocation of external services).

In the demo, object type ‘Album’ has references to object types ‘Artist’ and ‘Track’, hence, field resolvers for retrieval of artist by its ID (Album.artistId) and track by its ID (Album.trackId) should be implemented. In Spring, this is done by developing beans that implement interface GraphQLResolver, where appropriate methods implement referred entity retrieval logic.

 

Queries

We are now ready to finalize development of the demo application by implementing earlier declared query.

In Spring, this is done by developing beans that implement interface GraphQLQueryResolver, where appropriate methods implement corresponding query types.

 

Interaction with MongoDB service

There is one more bit that hasn’t been covered yet – interaction of the developed application with MongoDB. It is not related to the main subject of the blog, but is worth having a look at. As mentioned earlier, Spring provides convenient mechanism of interaction with cloud platforms’ services – Spring Cloud Connectors. From code snippets above, it can be seen that the application uses fairly standard approach for accessing MongoDB collections and documents in them – it utilizes template pattern (MongoTemplate, when being applied to MongoDB). Alternatively, Spring Data based approach (which utilizes CrudRepository – or, MongoRepository, when applied to MongoDB) could have been used. The one may notice that there has been no explicit declaration of MongoDB service location in application configuration – and this is where Spring Cloud Connectors become handy for implicit configuration required for successful initialization and instantiation of respective beans injected for specific cloud platform’s services.

In the demo, configuration for connectors is done in a simplistic way – by defining placeholder configuration bean that scans for all services that are available for the application using annotation ‘@ServiceScan’. In more complex and precise configuration, this bean could have been enhanced with injection of beans specific to particular needed services by extending abstract class AbstractCloudConfig, combined with custom tuning and tweaks, should this be required.

 

Build and deployment

After development is completed, the application is built and deployed to Cloud Foundry environment of SCP. Prior to application deployment, MongoDB service instance has been created, so that service binding could be created for the deployed application:

 

Client-side demo: querying GraphQL API

Explore GraphQL API using GraphiQL

Earlier described GraphQL runtime engine can be complemented with another helpful tool – GraphiQL – that can be deployed together with GraphQL runtime engine and can be used as web-based interactive browser for testing GraphQL queries.

To embed GraphiQL in the developed application, following dependency should be added: artifact ID ‘graphiql-spring-boot-starter’ of group ID ‘com.graphql-java’.

The tool provides auto-discovery and auto-completion functionalities based on available GraphQL schemas, as well as constructed query syntax check:

This becomes very handy when it comes to rapid testing of GraphQL queries and checking results of their execution based on developed query implementation and accessed data.

 

To conclude this outlook, below two examples of queries are provided to illustrate earlier mentioned behaviour of field resolvers at runtime.

The first query is as seen on the screenshot above and aims retrieval of album, artist and tracks data:

{
  album(title: "Imagine") {
    title
    genre
    year
    artist {
      name
      country
      notes
    }
    tracks {
      number
      title
    }
  }
}

Checking application logs for this query execution, we can see evidences of both field resolver methods invocations:

Next, we reduce the original query in such a way that it only retrieves fields of the artist entity:

{
  album(title: "Imagine") {
    title
    genre
    year
  }
}

Checking application logs for this new query execution, we can see that no field resolver methods were invoked, since no fields of corresponding related entities were requested by the query:

 

Query GraphQL API

There are several options how the developed GraphQL API can be consumed / queried. “Raw” low-level options are based on composition of corresponding HTTP requests and sending them to GraphQL endpoint of the application (by default, it is ‘/graphql’):

  • GET request with the URL parameter ‘query’ containing the entire GraphQL query,
  • POST request with the entire GraphQL query being placed in the JSON formatted body of the request.

 

Below examples demonstrate sample GET and POST requests that were constructed for the same GraphQL query as illustrated earlier when discussing GraphiQL, both requests were executed using Postman.

 

GET request

Request URL: https://graphql.cfapps.eu10.hana.ondemand.com/graphql?query={album(title:”Imagine”){title,genre,year,artist{name,country,notes},tracks{number,title}}}

 

POST request

Request URL: https://graphql.cfapps.eu10.hana.ondemand.com/graphql

Request body:

{
	"query": "{album(title: \"Imagine\"){title genre year artist {name country notes} tracks {number title}}}"
}

 

More high-level options involve usage of GraphQL client libraries that have been developed for various programming languages and frameworks. The primary advantage of usage of specific libraries is avoidance of manual composition of well-formed HTTP requests and convenient APIs that such libraries expose for construction and manipulation with complex queries in a more developer-friendly way, which might also become handy when it comes to support, maintenance and enhancement of applications that make use of complex queries.

To report this post you need to login first.

4 Comments

You must be Logged on to comment or reply to a post.

    1. Vadim Klimov Post author

      Hi Nikolay! Nice to see you here. Glad you found the content interesting! Next probable topic might be now, how to consume GraphQL APIs from PI/PO or CPI.

      (1) 
  1. Former Member

    Thank you for the article. It gave me new information that I can learn 🙂

    can you please help me with Spring Cloud Connectors? In case if I have two or more MongoDB services, but with different names, how can I define what MongoDB I would like to use?

    thanks

     

    (0) 
    1. Vadim Klimov Post author

      Hi Vlad,

      Thanks for your feedback – nice to hear that!

      Regarding usage of multiple instances of the service service type that are bound to an application… As a more advanced option of scanning for available services done by Spring Cloud Connectors, it is possible to use manual configuration, which involves inheritance from class AbstractCloudConfig, and usage of connection factory to obtain beans for specific bound instances of services by referring to them by service instance ID (and in that way, managing each service instance via corresponding bean, where we will have one to one mapping between service instance and bean). Having done so, we can then autowire and use corresponding beans by their qualifiers. There is an example of this approach described in Cloud Foundry documentation on service binding for Spring applications.

      Regards,

      Vadim

      (0) 

Leave a Reply