Lilo the stitching library for GraphQL
Tags: java, graphql, stitching
Published: 2022-09-18 11:01:58

---
title: Lilo the stitching library for GraphQL
published: true
description: 
tags: java, graphql, stitching
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bvs31qcrmfwp92uh9x3p.jpeg
---

The story is a well-known Not Invented Here syndrome among developers. Let me summarize from the beginning. Reverse proxies are good especially if you are using REST API, Even if you have multiple microservices behind the proxy. You can efficiently serve all your REST API via using an API Gateway. You can even make some transformation magic, authorization, aggregation, and plenty of other custom flavors. The sky is the limit.

But when it comes to GraphQL, it's not that easy. Especially if you want to transform a legacy code base without changing thousands of lines in frontend. You have 2 options one of them is GraphQL Federation which is a good practice to go with it. But it combines the methods in namespaces, so you might need some refactoring on frontend as well. The second option is GraphQL stitching.

I chose the stitching option. Then I stuck with Atlassian Braid which is a really handy tool TBH. But it seems deprecated and has not been touched for a while. Especially issues sections, there are plenty of bugs reported or questions from 3 years back. I was also trying to use Atlassian Braid on Spring Cloud Gateway. It was really good at the beginning till we deployed it on production. Because of the complex reactive streams logic on the Gateway. It causes lots of thread starvation or unresponsiveness. That eventually triggered me to implement a new one.

Like most of the developers, my estimation was wrong. I've estimated it as a weekend project then it turns out a complete level. then I ended up with [Lilo Stitching library](https://github.com/friatech/lilo/) and here we are.

## How GraphQL Stitching works

![How GraphQL Stitching works](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8t6l6u9u7m7zntuery6l.png)

When the Stitching library starts, it fetches the schema from the target schema sources, They might be a remote schema source or an internal source as well. After that, it maps all the GraphQL mutations and queries with respective sources.

For every incoming request, it analyzes the query and redirects the requests to respective schema sources after that it combines all the results and returns an aggregated result as a GraphQL response.

## Example usage

### Installation

Required dependency should be added to your project if you're using `maven` then you can add it into your `pom.xml` file:

```xml
<dependencies>
  ...
  <dependency>
    <groupId>io.fria</groupId>
    <artifactId>lilo</artifactId>
    <version>23.11.1</version>
  </dependency>
  ...
</dependencies>
```

If you're using `gradle` then you can add the dependency in your `build.gradle` file.

```groovy
implementation 'io.fria:lilo:23.11.1'
```

### Creating the source applications

You can use lilo with various libraries and web frameworks but I'll try to show a basic usage with spring boot. We need to create two different service projects for exhibiting lilo's skills. Thanks to GraphQL spring project we have now the ability to create GraphQL controller via using annotations just like the REST API.

Controller for Service Application1:

```java
@Controller
public class GreetingController {

  @QueryMapping
  public @NonNull String greeting1() {
    return "Hello world";
  }
}
```

Then we are going to create a similar controller for our second application:

```java
@Controller
public class GreetingController {

  @QueryMapping
  public @NonNull String greeting2() {
    return "Hello world";
  }
}
```

We also need to add GraphQL schema definition into `resources/graphql` directory. For Application1:

```graphql
type Query {
    greeting1: String
}
```

same for the application 2:

```graphql
type Query {
    greeting2: String
}
```

The package hierarchy should be something like this for both applications:

```
├── pom.xml
└── src
    └── main
        ├── java
        │   └── com
        │       └── example
        │           └── stitching_sample
        │               └── server1
        │                   ├── BssServer1Application.java
        │                   └── GreetingController.java
        │                       
        └── resources
            ├── application.properties
            └── graphql
                └── schema.graphqls
```

It might be wise to assign different port numbers in your `application.properties` or `application.yml` using `server.port`. We will be using `8081` for application 1 and `8082` for application 2.

# Creating the gateway

We will be using lilo inside a GraphQL REST controller but you can use it via a filter or you can use it with different web frameworks as well.

```java
@Controller
public class LiloController {

  private static final String SERVER1_NAME = "SERVER1";
  private static final String SERVER1_BASE_URL = "http://localhost:8081";
  private static final String SERVER2_NAME = "SERVER2";
  private static final String SERVER2_BASE_URL = "http://localhost:8082";

  private final Lilo lilo;

  public LiloController() {

    this.lilo =
        Lilo.builder()
            .addSource(
                RemoteSchemaSource.create(
                    SERVER1_NAME,
                    new IntrospectionRetrieverImpl(SERVER1_BASE_URL),
                    new QueryRetrieverImpl(SERVER1_BASE_URL)))
            .addSource(
                RemoteSchemaSource.create(
                    SERVER2_NAME,
                    new IntrospectionRetrieverImpl(SERVER2_BASE_URL),
                    new QueryRetrieverImpl(SERVER2_BASE_URL)))
            .build();
  }

  @ResponseBody
  @PostMapping("/graphql")
  public @NonNull Map<String, Object> stitch(@RequestBody final @NonNull GraphQLRequest request) {
    return this.lilo.stitch(request.toExecutionInput()).toSpecification();
  }
}
```

When the controller starts, it will create a combined GraphQL schema using the remote sources and it will execute incoming requests using lilo.

We also need additional Retriever definitions. Those classes retrieve the schema or query results. `IntrospectionRetriever` retrieves the remote schema and `QueryRetriever` is used for every single request for communicating and executing a single query or a mutation on the remote site.

```java
class IntrospectionRetrieverImpl implements SyncIntrospectionRetriever {

  private final String schemaUrl;
  private final RestTemplate restTemplate;

  IntrospectionRetrieverImpl(final @NonNull String schemaUrl) {
    this.schemaUrl = schemaUrl + "/graphql";
    this.restTemplate =
        new RestTemplateBuilder()
            .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
            .build();
  }

  @Override
  public @NonNull String get(
      final @NonNull LiloContext liloContext,
      final @NonNull SchemaSource schemaSource,
      final @NonNull String query,
      final @Nullable Object localContext) {

    return Objects.requireNonNull(
        this.restTemplate.postForObject(this.schemaUrl, query, String.class));
  }
}
```

and we also need to define our `QueryRetriever`

```java
class QueryRetrieverImpl implements SyncQueryRetriever {

  private final String schemaUrl;
  private final RestTemplate restTemplate;

  QueryRetrieverImpl(final @NonNull String schemaUrl) {
    this.schemaUrl = schemaUrl + "/graphql";
    this.restTemplate =
        new RestTemplateBuilder() //
            .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) //
            .build(); //
  }

  @Override
  public @NonNull String get(
      final @NonNull LiloContext liloContext,
      final @NonNull SchemaSource schemaSource,
      final @NonNull GraphQLQuery graphQLQuery,
      final @Nullable Object localContext) {

    return Objects.requireNonNull(
        this.restTemplate.postForObject(this.schemaUrl, graphQLQuery.getQuery(), String.class));
  }
}
```

now we are ready we can run all 3 applications and see the results.

```shell
curl -X POST \
    -H 'content-type: application/json' \
    -d '{"query":"{\ngreeting1\ngreeting2\n}","variables":null}' \
    http://localhost:8080/graphql
```

greeting1 will be executed on application1 and greeting2 will be executed on application2 we will get the results in a combined GraphQL response.

You can take a look at the sample implementation code on the official Lilo repo. [Check out the sample](https://github.com/friatech/lilo/tree/main/samples/lilo/02-spring-boot-basic-stitching)