Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Amazon Product Advertising API signed request with Java

after many hours of tinkering and reading the whole internet several times I just can't figure out how to sign requests for use with the Product Advertising API.

So far I managed to generate a client from the provided WSDL file. I used a tutorial by Amazon for this. You can find it here:

Tutorial for generating the web service client

So far no problems. To test the client I wrote a small piece of code. The code is intended to simply get some information about a product. The product is specified by its ASIN.

The code:

package client;

import com.ECS.client.jax.AWSECommerceService;
import com.ECS.client.jax.AWSECommerceServicePortType;
import com.ECS.client.jax.ItemLookup;
import com.ECS.client.jax.ItemLookupResponse;
import com.ECS.client.jax.ItemLookupRequest;

public class Client {

  public static void main(String[] args) {
    System.out.println("API Test startet");

    AWSECommerceService service = new AWSECommerceService();
    AWSECommerceServicePortType port = service.getAWSECommerceServicePort();

    ItemLookupRequest itemLookup = new ItemLookupRequest();
    itemLookup.setIdType("ASIN");
    itemLookup.getItemId().add("B000RE216U");

    ItemLookup lookup = new ItemLookup();
    lookup.setAWSAccessKeyId("<mykeyishere>");
    lookup.getRequest().add(itemLookup);

    ItemLookupResponse response = port.itemLookup(lookup);

    String r = response.toString();
    System.out.println("response: " + r);

    System.out.println("API Test stopped");
  }
}

As you can see there is no part where I sign the request. I have worked my way through a lot of the classes used and found no methods for signing the request.

So, how to sign a request?

I actually found something in the documentation: request authentication

But they don't use their own API. The proposed solutions are more or less for manual use only. So I looked in the client classes to sort out if I could get the request URL and put all the parts needed for request signing in myself. But there are no such methods.

I hope someone can point out what I am doing wrong.


This is what I did to solve the problem. All the credit goes to Jon and the guys of the Amazon forums.

Before I outline what I did, here is a link to the post which helped me to solve the problem: Forum Post on Amazon forums.

I downloaded the awshandlerresolver.java which is linked in the post. Than I modified my own code so it looks like this:

package client;

import com.ECS.client.jax.AWSECommerceService;
import com.ECS.client.jax.AWSECommerceServicePortType;
import com.ECS.client.jax.ItemLookup;
import com.ECS.client.jax.ItemLookupResponse;
import com.ECS.client.jax.ItemLookupRequest;

public class Client {

  public static void main(String[] args) {
    System.out.println("API Test startet");

    AWSECommerceService service = new AWSECommerceService();
    service.setHandlerResolver(new AwsHandlerResolver("<Secret Key>"));  // important
    AWSECommerceServicePortType port = service.getAWSECommerceServicePort();

    ItemLookupRequest itemLookup = new ItemLookupRequest();
    itemLookup.setIdType("ASIN");
    itemLookup.getItemId().add("B000RE216U");

    ItemLookup lookup = new ItemLookup();
    lookup.setAWSAccessKeyId("<Access Key>"); // important
    lookup.getRequest().add(itemLookup);

    ItemLookupResponse response = port.itemLookup(lookup);

    String r = response.toString();
    System.out.println("response: " + r);   
    System.out.println("API Test stopped");
  }
}

The println on the end are more or less useless. But it works. I also used the WSDL Jon linked to generate a new webservice client. I just changed the URLs in the tutorial I posted in my question.

like image 668
Jens Avatar asked Jul 06 '10 20:07

Jens


2 Answers

Try this afer you create the service

service.setHandlerResolver(new AwsHandlerResolver(my_AWS_SECRET_KEY));

You'll need this class and this jar file to add as a reference to your project as AwsHandlerResolver uses Base64 encoding.

You'll need to rename the AwsHandlerResolver file to the name of the class as the file name is all lower case.

I think the rest of the code you have is fine.

The WSDL is http://webservices.amazon.com/AWSECommerceService/AWSECommerceService.wsdl

like image 94
Jon Avatar answered Oct 29 '22 00:10

Jon


This discussion and the related Amazon post helped me get the client working. That being said, I felt that the solution could be improved with regards to the following:

  1. Setting WebService handlers in code is discouraged. A XML configuration file and a corresponding @HandlerChain annotation are recommended.
  2. A SOAPHandler is not required in this case, LogicalHandler would do just fine. A SOAPHandler has more reach than a LogicalHandler and when it comes to code, more access is not always good.
  3. Stuffing the signature generation, addition of a Node and printing the request in one handler seems like a little too much. These could be separated out for separation of responsibility and ease of testing. One approach would be to add the Node using a XSLT transformation so that the handler could remain oblivious of the transformation logic. Another handler could then be chained which just prints the request. Example
like image 42
Abhijit Sarkar Avatar answered Oct 29 '22 00:10

Abhijit Sarkar