Rescuscitating AMM with Amazon Web Service signed requests

Wednesday, August 26th, 2009

A few days ago Amazon added a requirement to their AWS that all requests to the service be signed, lest they be rejected. I’ve been using Sozu’s excellent Amazon Media Manager plugin for a while now to manage the currently reading list on this blog. It’s been a great way to keep track of exactly what I have read (avoiding the need to, like, remember), as well as masking my illiteracy by pasting a giant list of what is commonly known as airport trash.

Unfortunately, this is one plugin that hasn’t been updated in quite a while (after all, if ain’t broke…), so it broke. Being the sort of developer that’s quite happy to pick up a block of php and hack it until it works, I stumbled across this blog entitled ‘AmazonĀ® AWS HMAC signed request using PHP‘, which has a function to download.

So to fix AMM:

1. Download that file, and copy the contents into the bottom of amm_parser.php.

2. In the same file (amm_parser.php), replace your _setUrl function with this one:

function &_setUrl() {
	//Build URL from base URL and other required parameters
	switch ($this->_locale) {				
		case 'uk':
			$region = 'co.uk';
			break;
		case 'de':
			$region .= 'de';
			break;
		case 'jp':
			$region .= 'co.jp';
			break;
		case 'fr':
			$region .= 'fr';
			break;
		case 'ca':
			$region .= 'ca';
			break;
		case 'us':
		default:
			$region = 'com';
			break;
	}
	$public_key = "< < Your Access Key ID >>";
	$private_key = "< < Your Secret Access Key >>";
	$url = aws_signed_request($region, array(
			"Operation"=> "ItemSearch",
			"Keywords" => $this->_parameters[Keywords],
			"ResponseGroup"=>$this->_parameters[ResponseGroup],
			"SearchIndex" => $this->_parameters[SearchIndex],
			"AssociateTag" => urlencode($this->_associate_tag)),
			$public_key, $private_key);
	return $url;
}

3. Oddly enough, this new method requires a private secret key which Amazon recommends to not give to anyone. So I’m not going to post mine here, even though it’s required for the plugin to work. So before I ponder that particular nugget of madness, you’ll need to sign up for an AWS developer account, and find your own keys via the Access Identifiers page. These need to be added into the function above.

That should be enough to get you back up and running again, although selfishly I’ve only really tested it for my needs alone. So please let me know if it works, or fails miserably.

For all the legal bits, I’m not at all affiliated with Amazon or Sozu – so please use at your own risk :)

Getting document reports from Amazon Seller Central SOAP services (C#)

Sunday, March 22nd, 2009

Developing against the Amazon API becomes a lot more straightforward with being able to get at the errors with your XML documents. Validating against the XSDs is only part of the solution, but even downloading reports can be tricky. Trouble is, the documentation from Amazon is a very closed & private sort of affair – sometimes out of date and sometimes very sparse. Perhaps they should think about a wiki :)

Getting at your reports consists of two parts, firstly – use the Document ID (long) you got from posting the XML in the first place.

public DocumentProcessingInfo DocumentStatus(long DocumentID)
    {
        //Setup the service interface, set the URL of the service
        //and add our credentials.
        merchantinterfacedime myAmazon =
            new merchantinterfacedime();
        myAmazon.Url = ConfigurationManager.AppSettings["URL"];
        myAmazon.Credentials =
            new NetworkCredential(
                ConfigurationManager.AppSettings["UserName"],
                ConfigurationManager.AppSettings["Password"]);
        //Setup our merchant details.
        Merchant myMerchant = new Merchant();
        myMerchant.merchantIdentifier =
            ConfigurationManager.AppSettings["MerchantIdentifier"];
        myMerchant.merchantName =
            ConfigurationManager.AppSettings["MerchantName"];
        //Send it all off to Amazon.
        DocumentProcessingInfo myStatus =
            myAmazon.getDocumentProcessingStatus(
            myMerchant, DocumentID);
        //Return the status of the document.
        return myStatus;
    }

This will give you the status of your upload, as well as whether it’s complete or not. It also gives you another document ID, which you can use to get at your much-needed reports.

public string GetDocument(string id) {
        StringBuilder report = new StringBuilder();
        merchantinterfacedime myAmazon =
            new merchantinterfacedime();
        myAmazon.Url = ConfigurationManager.AppSettings["URL"];
        myAmazon.Credentials =
            new NetworkCredential(
                ConfigurationManager.AppSettings["UserName"],
                ConfigurationManager.AppSettings["Password"]);
        //Setup our merchant details.
        Merchant myMerchant = new Merchant();
        myMerchant.merchantIdentifier =
            ConfigurationManager.AppSettings["MerchantIdentifier"];
        myMerchant.merchantName =
            ConfigurationManager.AppSettings["MerchantName"];
        ReferencedBinary incomingDoc = new ReferencedBinary();
        // the seven-digit string is the document ID number
        myAmazon.getDocument(myMerchant, id, out incomingDoc);
        IEnumerator enumer = myAmazon.ResponseSoapContext.Attachments.GetEnumerator();
        while (enumer.MoveNext())
        {
            // Print the document to standard out
            Attachment downloadedDoc = enumer.Current as Attachment;
            StreamReader r = new StreamReader(downloadedDoc.Stream);
            report.Append(r.ReadToEnd());
        }
        return report.ToString();
}

And tying it all together:

long amazonId = #######
string report = GetDocument(DocumentStatus(amazonId).processingReport.documentID);

Your report will be in XML, and give you any validation errors that might be preventing your feed from working properly, as well as some very helpful status on the number of items processed. How did you ever live without it?