Amazon Web Services (AWS) provides a powerful tool for finding and evaluating just about any type of material goods. Whether you are searching by keywords or the UPC code, AWS can provide just about all the information you will ever need to know about a product. However, Amazon has put a lot of hurdles between you and the information you needs. First, as of August 15, 2009, AWS now requires that you sign all your requests. Secondly, they have terrible documentation and confusing error messages that do not always explain how to fix the problem.
Amazon Web Services Utility is a YUI 3 JavaScript/PHP solution that simplifies interacting with AWS by handling the request signing process automatically and securely, and prevening or handling common errors. In addition to returning the result as XML, there is an additional gallery-aws-json
package that adds functionality to parse the XML data into JSON objects.
Step 1: Getting Started
The first thing you need to do is get an AWS account (if you dont already have one).awsSignedUrlThen go to the "Your Account" tab and the "Security Credentials" link. If you do not have an "Access Key" setup, click the "Create a new Access Key" link and create one. You will need both the "Access Key ID" and the "Secret Access Key" for your Amazon Web Services Utility.
Then download the following 4 files:
http://code.google.com/p/yui-ext-mvc/source/browse/trunk/getAWSSignedUrl.txt (change extension to ".php")
http://code.google.com/p/yui-ext-mvc/source/browse/trunk/assets/js/yahoo-3-ext/aws.js
http://code.google.com/p/yui-ext-mvc/source/browse/trunk/assets/js/yahoo-3-ext/aws-json.js
http://code.google.com/p/yui-ext-mvc/source/browse/trunk/assets/files/io.swfStep 2: getAWSSignedUrl.php
This file is used to securely create the AWS signed url and should be placed on the web-server you wish to use AWS Utility on. You will need to replace "YOUR_PUBLIC_ACCESS_KEY_ID" and "YOUR_SECRET_ACCESS_KEY" with the ones you created in Step 1. You may also want to replace the$associateTag
value with your own associate tag, if you want to be paid anytime someone purchases a product on Amazon using the links generated by this utility.Ulrich Mierendorff wrote the algorithm that we are using to sign the URLs in
aws_signed_request
by creating a hash of the request you wish to make using HMAC with SHA256 and base64-encoding.The signing algorithm is server-side because we do not want our secret access keys available to public, and therefore they cannot be in JavaScript. So anytime we want to make an AWS request, two AJAX requests are required: one to "getAWSSignedUrl.php" to fetch the AWS signed URL, and then one using the signed URL to AWS.
Step 3: aws.js
TheY.Aws
has 4 configuration properties:awsSignedUrl
is the URL for the "getAWSSignedcUrl.php" and defaults to/getAWSSignedUrl.php
;ioSWFURL
is the URL for the XDR SWF (required to use JavaScript to make cross-domain request) and defaults to/assets/files/io.swf
;operation
is the type of AWS Operation to make and defaults toItemLookup
, which is used for ISBN, UPC, and ASIN searches;responseGroup
is the type of AWS response you would like and defaults toSmall
, which contains most of the relevant information about a product. To use the utility, simply call thegetXML
function.getXML: function(conf, callback, ctx) { if (_isReady) { var cfg = Y.Lang.isObject(conf) ? conf : {}, url = this.get(
), operation = this.get(operation
), responseGroup = this.get(responseGroup
), context = ctx || this; if (_timer) {_timer.cancel();} // build URL to fetch AWS URL if (-1 === url.indexOf(?
)) {url +=?
;} url +=&ResponseGroup=
+ responseGroup +&Operation=
+ operation; Y.each(cfg, function(value, key) { url +=&
+ key +=
+ value; }); // fetch AWS URL Y.io(url, {on: {success: function(id,o) { try { // parse AWS URL var data = Y.JSON.parse(o.responseText); if (! data.aws_request) { // todo: update message to show missing parameters alert(AWS request is missing required parameters
); return; } Y.io(data.aws_request, {context: context, on:{success: function(id,o) { // this is intentional, I cannot get "Y.DataSchema.XML" to work with namespaces var responseText = o.responseText.replace(/xmlns=".*?"/,
), code, msg; // remove the namespace o.responseXML = Y.DataType.XML.parse(responseText); // convert to XML code = o.responseXML.getElementsByTagName(Code
)[0]; msg = o.responseXML.getElementsByTagName(Message
)[0]; // show AWS errors if (code && msg && code.firstChild.nodeValue) { alert(code.firstChild.nodeValue + "\n" + msg.firstChild.nodeValue); return; } callback.apply(this, arguments); }}, xdr:{/*dataType:xml
, */responseXML:false, use:flash
}}); } catch (e) { alert(Call to getAWSSignedUrl was not parsable
); } }}}); } else { _timer = Y.later(_timeoutLength, this, this.getXML, arguments); _timeoutLength += _timeoutStep; } }AWS request is missing the response typeThere are three parameters to passing into this function:
conf
the parameters to use for the request,callback
the callback function to execute when AWS data returns, andctx
the execution context of the callback. The function first checks if the XDR SWF is ready, then fetches a few parameters from the configuration. Using those parameters and the providedconf
a URL is constructed. That URL is passed to "getAWSSignedUrl.php" and signed. If "getAWSSignedUrl.php" validated the URL and successfully signed it, a request is make to AWS using the XDR SWF. When that returns the XML namespace needs to be removed as there is a bug withY.DataSchema.XML
that causes it to not be able to parse the XML when a namespace is defined. If there was an error message, then it is shown, otherwise the arguments and context are all passed into the callback function. The callback function should expect the same parameters that are returned from any YUI 3 IO call.Step 4: aws-json.js
This addon augments theY.Aws.prototype
with a new methodgetJSON
, which accepts the same parameters asgetXML
. The difference is that the object passed as the second argument of the callback will also have aresponseJSON
object in addition toresponseText
andresponseXML
. This JSON object will be the parsed XML, and changes depending on the ResponseGroup used. Currently only "Medium", "Small", and the several ResponseGroups that make those two up are supported. Until I finish implementing a parse for all ResponseGroups, it might be best to usegetXML
if you know you are going to need something that is unsupported.getJSON: function(item, callback, ctx) { this.getXML(item, function(id, o) { if (o.responseXML) { var json = this._parseAWSContent(o.responseXML); if (json) { o.responseJSON = json; callback.apply(ctx, arguments); } else { alert(
); } } else { alert(AWS request failed.
); } }, ctx); }, _parseAWSContent: function(doc) { var args = Y.DataSchema.XML.apply(AWS_SCHEMA.args, doc), response =
, responseGroup = Y.Array.find(args.results, function(arg) { return NAME_RESPONSE_GROUP === arg.name; }); if (responseGroup.value) { response = Y.DataSchema.XML.apply(AWS_SCHEMA[responseGroup.value], doc); } return response; }978-0470227800The
getJSON
function leveragesgetXML
, and simply parses the XML using_parseAWSContent
ifresponseXML
is available. The parsing function usesY.DataSchema.XML
to parse the XML. There various schemas available are ordered by ResponseGroup in the beginning ofaws-json.js
.Using AWS Utility
var aws = new Y.Aws(); // using defaults // fetch XML aws.getXML({ItemId:
, IdType:UPC
}, function(id, o) { // your code, using o.responseXML }); // fetch JSON aws.getJSON({ItemId:978-0470227800
, IdType:UPC&rsquot;}, function(id, o) { // your code, using o.responseJSON });
This will fetch "Professional JavaScript for Web Developers" by Nichalos Zakas from AWS. I have also included an AWS Test Page so you can play around with your own searches.