Consuming a JSON API - Part 1 (Retrofit)

Jul 15th, 2015 in  by Michael Cho

Square's Retrofit library together with EventBus makes it super simple to parse the contents of a JSON API into your Android app.

Many mobile apps retrieve data from a server via an API, and then updates one or more screens with the results from the API call. The two main steps in this are:

  1. Connecting with the API
  2. Using the results in your app

This article will cover using Retrofit, the first step. In the next article, we'll look at EventBus for step 2. In particular, we are going to send a GET request to an API endpoint and parse the JSON results (see sample response) for our app. My example is for a simple app for a community forum with submissions and comments.

Retrofit to API

Note: Although I am using Retrofit as my HTTP Client library, you may also want to explore Volley.  

Installing Retrofit is done by simply adding compile 'com.squareup.retrofit:retrofit:1.9.0' to my gradle file. From there, I created a class in api/MyAPI which looks like this:


package my.app.name.api;

import retrofit.Callback;
import retrofit.http.GET;
import retrofit.http.Path;


public interface MyAPI {

  @GET("/v/{forum}/{submissionID}/comments")
  void getComments(@Path("forum") String forum, @Path("submissionID") int submissionID, Callback<CommentsResponse> cb);

}

What we have done here is setup an interface to the API, which exposes calls an API endpoint like http://myapi.com/v/forum/123/comments when you call the getComments() method in your app. This will return the JSON response to a CommentsResponse callback (not yet created). There are two parameters to pass to getComments(), which are a String for the forum name, and an integer for the submission ID. The response will then be an array of all the comments for this submission.

CommentsResponse class

The CommentsResponse class is a simple class which maps the JSON response with your app's data models. From the sample json, you can see the response only has 2 nodes - success which is a simple string and data which is an array of comment objects. So my api/CommentsResponse class looks like this:


package my.app.name.api;

import java.util.List;

import my.app.name.models.Comment;

public class CommentsResponse {
  public String success;
  public List<Comment>data;
}

This creates a List of Comment objects from the API response. Provided your Comment model has attributes which match the JSON keys in the data array, all Comment objects will be instantiated with their correct attributes. Here is what my Comment model looks like:


package my.app.name.models;

public class Comment {
  public Comment(){}

  public int id;
  public int parentID;
  public int submissionID;
  public String subverse;
  public String date;
  public int upVotes = 0;
  public int downVotes = 0;
  public String userName;
  public int childCount;
  public String content;
  public String formattedContent;
}

Now that all the setup is done, how do we actually make calls to the API? Well I chose to do it from another model like so:


import my.app.name.api.MyAPI;
import retrofit.RequestInterceptor;
import retrofit.RestAdapter;

public class Submission(){
  public Submission(){}
  public int id;
  public String forum;
  private String API_KEY = "abc123";
  private String BASE_URL = "http://myapi.com";

  public void fetchComments(){

    // This API requires a key to be sent in the headers.
    RequestInterceptor requestInterceptor = new RequestInterceptor() {
      @Override
      public void intercept(RequestFacade request) {
        request.addHeader("Voat-ApiKey", API_KEY);
      }
    };

    // Add interceptor when building adapter
    RestAdapter restAdapter = new RestAdapter.Builder()
        .setEndpoint(BASE_URL)
        .setRequestInterceptor(requestInterceptor)
        .build();

    MyAPI api = restAdapter.create(MyAPI.class);

    api.getComments(this.forum, this.id, new Callback<CommentsResponse>() {
      @Override
      public void success(CommentsResponse commentsResponse, Response response) {
        comments = commentsResponse.data;
        EventBus.getDefault().post(new CommentsReceived(comments));
      }

      @Override
      public void failure(RetrofitError error) {
        Log.e("Subverse Retrofit", error.toString());
      }
    });

  }
}

This means that any Submission object has a fetchComments() method which calls to the API and retrieves an array of Comment objects. In the success callback, we use EventBus to notify any activity screens that a new list of Comments have been received. More on this to come in the next article.


Other articles you may like

Debugging mobile apps with Charles proxy
Aug 15th, 2016
Consuming a JSON API - Part 2 (EventBus)
Jul 30th, 2015
Simple Android utility to parse config files in your app
Jun 19th, 2015
Android swipe to refresh, only at the top of the list
Jun 10th, 2015
Creating an instant autocomplete field in Android
Jun 2nd, 2015