How to Handle Advanced Requests on Android with GraphQL &RxJava
Tags: graphql, android, rxjava, apollo
Published: 2021-08-02 13:40:27

## Introduction

Welcome to part two of my series on GraphQL, Android, and RxJava! If you haven’t already, be sure to check out my [part one article](https://levelup.gitconnected.com/apollo-rxjava-android-graphql-the-right-way-a1f2b10a9ac8) where I go over the basics of using RxJava with GraphQL on Android. In this article, we’ll go over some more advanced topics, such as handling parallel and dependent requests. Let’s get to it!

## Setup

We’re going to continue using the Android app we setup in my last article for the examples here. We’ll continue using the SpaceX GraphQL API for this article as well. Particularly, the `rocket` and `launchpads` queries. Let’s start off by writing GraphQL queries for these endpoints.

First, the `rocket` query:
```graphql
query RocketQuery($id: ID!) {
    rocket(id: $id) {
        id
        name
        description
        first_flight
        cost_per_launch
    }
}
```
This should be pretty familiar if you’ve [read my previous article](https://levelup.gitconnected.com/apollo-rxjava-android-graphql-the-right-way-a1f2b10a9ac8), the only difference is the `$id` parameter we added. That’s used to specify which rocket we want to fetch, and we’ll use it later in our Java code.

Now the `launchpads` query:
```graphql
query LaunchPadsQuery {
    launchpads {
        vehicles_launched {
            id
        }
        name
    }
}
```
Nothing special here, just some good ole' GraphQL.

With our GraphQL queries written, all that’s left is to make methods for them in our Server class.

First, `rocket`:
```java
public static Observable<Response<RocketQuery.Data>> fetchRocket(String id) {
    ApolloQueryCall<RocketQuery.Data> call = getApolloClient()
            .query(new RocketQuery(id));

    return Rx3Apollo.from(call)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .filter((dataResponse -> dataResponse.getData() != null));
}
```
Again, this is pretty similar to our previous setup. However, notice the id argument in the method definition. We use that to set the `$id` argument we defined earlier in our GraphQL query file.

Next, `launchpads`:
```java
public static Observable<Response<LaunchPadsQuery.Data>> fetchLaunchPads() {
    ApolloQueryCall<LaunchPadsQuery.Data> call = getApolloClient()
            .query(new LaunchPadsQuery());

    return Rx3Apollo.from(call)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .filter((dataResponse -> dataResponse.getData() != null));
}
```
This one’s just like our other server methods. We create an `ApolloQueryCall`, use that to create a query object, and then convert it into an `Observable` so we can work our Rx magic.

That’s it for our Server class. You can reference the [repo version](https://github.com/Ninjaman494/Android-GraphQL-Example/blob/main/app/src/main/java/com/n494/spacex/Server.java) to make sure yours is setup correctly. With that done, we should be all set to dive into some advanced request scenarios.

## Scenario 1: Parallel Requests
Our first scenario is a very common one, parallel requests. Often times, we need to make multiple requests to get the data we need. In our case, we’re going to make a page that lists information about a rocket along with a list of launchpads it’s used. Since these requests are independent of each other, we should do them in parallel. The best way to handle this scenario is to do both requests in the beginning, show a loading indicator while we wait for a response, and then show the page once both requests are done. Using a combination of GraphQL and RxJava, doing this on Android becomes really easy.

First, let’s create an `Observable` of our `rocket` query:
```java
// Fetch Rockets
ObservableSource<Response<RocketQuery.Data>> observable = Server.fetchRocket(id);
```
Notice that we save this observable instead of immediately acting on it. That’s because we’re going to combine it with the our second request so we can act on the combined result. Don’t worry though, the request is made as soon as we call our `fetchRocket` method.

We then do our `launchpads` query and combine the two requests with `zipWith`:
```java

Server.fetchLaunchPads()
  .zipWith(observable, (BiFunction<Response<LaunchPadsQuery.Data>, Response<RocketQuery.Data> , Pair<RocketQuery.Rocket, List<String>>>)
    (launchPadsResponse, rocketResponse) - > {
      List<LaunchPadsQuery.Launchpad> launchpads = launchPadsResponse.getData().launchpads();
      RocketQuery.Rocket rocket = rocketResponse.getData().rocket();

      String rocketId = rocket.id();
      ArrayList<String> filteredPads = new ArrayList<>();

      for (LaunchPadsQuery.Launchpad launchpad: launchpads) {
        for (LaunchPadsQuery.Vehicles_launched vehicle: launchpad.vehicles_launched()) {
          if (vehicle.id().equals(rocketId)) {
            filteredPads.add(launchpad.name());
          }
        }
      }

      return new Pair<>(rocket, filteredPads);
    })
```
Here, we do our `launchpads` query and zip it with the `observable` from our previous query. The second argument is a function that describes how to combine the two request responses. In our case, we’ll first sort through the launchpads and only save the ones that were used by the rocket we wanna show. Then, we combine the data from the two requests into a `Pair`.

In this step of our pipeline, we’ve combined the responses from our requests into a new object. Our `zipWith` function won’t get called until both responses resolve, so all we have to worry about now is handling the combined result. At this point, it’s just like handling a regular request. We can just use `subscribeWith`:
```java
 // Once both requests have completed, handle the combined result
.subscribeWith(new DisposableObserver<Pair<RocketQuery.Rocket, List<String>>>() {
  @Override
  public void onNext(@NonNull Pair<RocketQuery.Rocket, List<String>> pair) {
    RocketQuery.Rocket rocket = pair.first;
    List<String> launchpads = pair.second;

    nameView.setText(rocket.name());
    flightView.setText(String.format("First flight was on %s", rocket.first_flight()));
    costView.setText(String.format("Cost per launch: $%s", rocket.cost_per_launch()));
    descView.setText(rocket.description());

    LaunchPadsAdapter adapter = new LaunchPadsAdapter(launchpads);
    recyclerView.setAdapter(adapter);
  }

  @Override
  public void onError(@NonNull Throwable e) {

  }

  @Override
  public void onComplete() {
    // Both requests have finished, so hide loading bar
    progressBar.setVisibility(View.GONE);
  }
});
```
Notice that the class definition uses `Pair<RocketQuery.Rocket,List<String>>` , this is the return type from our `zipWith` function and the types need to match for our pipeline to work. In `onNext` we use the `Pair` we created in `zipWith` to fill in our views with the response data. We then turn off the loading state in `onComplete` . For simplicity sake, I didn’t handle error state, but this can be easily done in the `onError` event handler. With this step our pipeline should be complete, you can double check your pipeline by checking out this [code file](https://github.com/Ninjaman494/Android-GraphQL-Example/blob/main/app/src/main/java/com/n494/spacex/RocketDetailsActivity.java).

Using Apollo Android and RxJava, we were able to handle parallel requests with ease. This could easily be scaled up to handle more parallel requests, just add another `zipWith` for each new request and update your `subscribeWith` accordingly.

## Scenario 2: Dependent Requests

In our last scenario, the two requests were independent of each other, but what if they weren’t? Sometimes we need to make multiple requests, but the second request requires data from the first request. In this scenario, we can’t run the requests in parallel, instead we have to run them sequentially.

This time we’re still going to display information about a rocket, but we only have the rocket’s name, not its id. That means that we first have to do a request to the `rockets` endpoint(see [my last article](https://levelup.gitconnected.com/apollo-rxjava-android-graphql-the-right-way-a1f2b10a9ac8)), get the id from the response, and then call `rocket` using that id. Handling this scenario on Android is a breeze with GraphQL and RxJava.

First, we’re going to query the `rockets` endpoint, and then use `concatMap` to handle the result:
```java
// Fetch rockets and use the response to fetch the rocket we want
Server.fetchRockets()
  .concatMap(dataResponse -> {
    assert dataResponse.getData() != null;

    List<RocketsQuery.Rocket> rocketList = dataResponse.getData().rockets();
    for (RocketsQuery.Rocket rocket : rocketList) {
      if (rocket.name().equals(ROCKET_NAME)) {
        return Server.fetchRocket(rocket.id());
      }
    }

    return null;
  })
```
Here, we use the `fetchRockets` method we created in my previous article, but handle it with `concatMap`. With `concatMap`, we can handle the response and then pass information down to the next step in our RxJava pipeline. First, we sort through the list to find the rocket we’re looking for. Once we find the right rocket, we use its id to make a request to our `rocket` endpoint.

Notice that we’re returning the `Observable` created by `fetchRocket`, that’s because we’ll use it in our next pipeline step, shown below:
```java
// Once response is received, handle result
.subscribeWith(new DisposableObserver<Response<RocketQuery.Data>>() {
  @Override
  public void onNext(@NonNull Response<RocketQuery.Data> dataResponse) {
    assert dataResponse.getData() != null;

    RocketQuery.Rocket rocket = dataResponse.getData().rocket();

    nameView.setText(rocket.name());
    flightView.setText(String.format("First flight was on %s", rocket.first_flight()));
    costView.setText(String.format("Cost per launch: $%s", rocket.cost_per_launch()));
    descView.setText(rocket.description());
  }

  @Override
  public void onError(@NonNull Throwable e) {

}

  @Override
  public void onComplete() {
    // Requests have finished, so hide loading bar
    progressBar.setVisibility(View.GONE);
  }
});
```
This code snippet should be all too familiar by now. Just like our other examples, we use `subscribeWith` to handle the response. You can check the completed pipeline [here](https://github.com/Ninjaman494/Android-GraphQL-Example/blob/main/app/src/main/java/com/n494/spacex/RocketDetailsByNameActivity.java). With RxJava, we can handle complex GraphQL requests on Android with ease.

## Conclusion
By taking advantage of the Apollo Android and RxJava libraries, we can handle some pretty complex request scenarios without difficulty. Be sure to check out this article’s [companion repo](https://github.com/Ninjaman494/Android-GraphQL-Example) for a more in depth look at the code. In my next article, I’ll talk about how to write Android instrumented tests for the GraphQL requests we’ve made. 

As always, thanks for reading and give me a :heart: if you enjoyed this article! I love seeing how my readers use what they’ve learned, so please share how you’re using these strategies in your own Android apps in the comments below.