Wednesday, May 14, 2014

Consuming Appnexus Country Service (and similar Read Only Services)

In the previous post, we have seen introduction to Appnexus and the technologies required to consume Appnexus API through Java. We have also seen the authentication mechanism using user name and password, which is a prerequisite for consuming any service to API. In the last post, we have also created a central Authentication Service which will take care of managing the life cycle of the authentication token and automatically renewing it when it expires, such that all the consumers get a valid authentication token.

In this post, we are going to see how we could leverage all that has been learned so far to read the list of countries from Appnexus.

Introduction to Country Service 

Appnexus provides a list of read-only services using which we could consume all the Meta data that are required for certain other services. The read-only Country Service allows you to see information about the countries registered in the AppNexus system. You can use this service to retrieve the country codes for targeting in campaigns.

Objectives 

  • Set up the necessary infrastructure that is required to consume the list of countries. 
  • Automatically add the authentication token using the authentication service. 


Quoted from Appnexus:

The following is a sample request given from commandline to fetch the list of countries. For more information on country service refer to the following link. https://wiki.appnexus.com/display/api/Country+Service

$ curl -b cookies -c cookies 'http://api.appnexus.com/country'
 
{
    "response": {
        "status": "OK",
        "count": 250,
        "start_element": 0,
        "num_elements": 100,
        "countries": [
            {
                "id": 1,
                "name": "Anonymous Proxy",
                "code": "A1"
            },
            {
                "id": 2,
                "name": "Satellite Provider",
                "code": "A2"
            },
            {
                "id": 3,
                "name": "Other Country",
                "code": "O1"
            },
            {
                "id": 4,
                "name": "Andorra",
                "code": "AD"
            },
            {
                "id": 5,
                "name": "United Arab Emirates",
                "code": "AE"
            },
            {
                "id": 6,
                "name": "Afghanistan",
                "code": "AF"
            },
            ...
        ],
        "dbg_info": {            
        }
    }
}

Required Components 

First of all, we have to create the interface that specifies the contract of Appnexus Country Service. Pay attention to the @GET annotation which specifies the endpoint of Country Service. Also note that we are passing start_element as a request parameter for each request, the reason for passing it is that, countries are returned to us in pages, and when we are fetching the subsequent page the start_element has to be appropriately specified.

AppnexusRestClient.java

public interface AppnexusRestClient {

 @GET("/country")
 ResponseContainer getCountryList(
   @Query("start_element") int startElement);
   
 // ... getters, setters
}

Modelling Response Object 

The following listings shows all the classes that are required for modelling the response returned by Appnexus. If you could compare the structure of the below classes with the JSON returned by Appnexus in the above example you could see that we have just mirrored the same structure using Java.

The below classes the outermost container, that just encapsulates the response object. It doesn't serve any other purpose. Kindly pay attention to the fact that this response container could contain any type of response, that's why it is parameterized by using generics.

public class ResponseContainer<T> {

 private T response;
 
 // ... getters, setters
}

The reason for creating abstract response is that, the format of response object is constant for almost every response, instead of repeating the same field again and again in all the response objects, this class would help avoid repetition.

public abstract class AbstractResponse {

 private String status;
 private DbgInfo dbgInfo;

 private String errorId;
 private String error;
 private String errorDescription;
 
 // ... getters, setters

}

The reason for creating the below class is that a few services like the Country Service for example returned the response in pages. Pay attention to the start_element, num_element and count in the response from Appnexus. Whenever the response is pagable, you'll have these fields as part of the response. So based on the value of these elements, we should determine whether there are more elements to be fetched and give subsequent requests accordingly. By having the below class, whenever we are requesting for an element which should be fetched in pages, we could use it.

public abstract class AbstractPagableResponse extends AbstractResponse {

 private Integer count;
 private Integer startElement;
 private Integer numElements;

 // ... getters, setters
}

Finally the below classes are the ones that are specific to the Country Service. These classes are self-explanatory.

public class CountryListResponse extends AbstractPagableResponse {

 private List<Country> countries;
 
 // ... getters, setters

}

public class Country {

 private Long id;
 private String name;
 private String code;
 
 // ... getters, setters
 
}

The following listing shows the procedure to create a new rest adapter and to send a request to Appnexus, followed by reading the response. Read the comments in the listing to understand what is happening in each of the steps.

// 1. create new gson
Gson gson =  new GsonBuilder()
 .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
    .create();
  
// 2. create a rest adapter  
RestAdapter restAdapter = new RestAdapter.Builder()
    .setEndpoint(appnexusApiEndpoint)
    .setRequestInterceptor(new RequestInterceptor() {

     @Override
     public void intercept(RequestFacade request) {
     
      // add authentication header here
      request.addHeader("Authorization",     authenticationService.getAuthenticationToken());
     }
    }).setConverter(new GsonConverter(gson)).build();

// 3. create a rest client
AppnexusRestClient client = restAdapter.create(AppnexusRestClient.class);

// 4. request for country list and get the response

int startElement = 0;
ResponseContainer responseContainer = client.getCountryList(startElement);

// 5. read the country list from response
List list = responseContainer.getResponse().getCountries();

Request Interceptor

In the above listing, in the second step you could see that a request interceptor is being added. Its purpose is to add the authorization header to the outgoing request.  This is exactly where the authentication token is fetched from the authentication service and it is being added to the request.

Retrieving Subsequent Pages

In the above samples, we have only seen how to retrieve the first page using a rest client. In the next post we will see how to consume all the available pages using Spring Batch.

Kindly post a comment if you either like it or if you feel the content is inappropriate in some way.

No comments :

Post a Comment