Skip to content

Instantly share code, notes, and snippets.

Created April 14, 2015 20:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/466ee04cbb57fd75d606 to your computer and use it in GitHub Desktop.
Save anonymous/466ee04cbb57fd75d606 to your computer and use it in GitHub Desktop.
Look up book author, title, and publisher by isbn in Amazon web services
-module (amz_lookup).
-export([http_by_isbn/1]).
% -compile(export_all).
-include_lib("xmerl/include/xmerl.hrl").
% NOTE: Macros blocked out to protect the innocent. Use your own.
-define(ASSOC_TAG, "AAAAAAAA").
-define(ACCESS_KEY, "XXXXXXXXX").
-define(SECRET_KEY, "YYYYYYYYYYYYYYYYYYYY")
%% Look up book author, title, and publisher by isbn in Amazon web services db.
%% http://docs.aws.amazon.com/AWSECommerceService/latest/DG/EX_LookupbyISBN.html
%% http://docs.aws.amazon.com/AWSECommerceService/latest/DG/rest-signature.html
%% Compute timestamp
pad_date(Int) when Int < 10 ->
"0" ++ integer_to_list(Int);
pad_date(Int) ->
integer_to_list(Int).
timestamp() ->
[{{Year, Month, Day},{Hour, Minute, Second}}] =
calendar:local_time_to_universal_time_dst(calendar:local_time()),
S = integer_to_list(Year) ++
"-" ++
pad_date(Month) ++
"-" ++
pad_date(Day) ++
"T" ++
pad_date(Hour) ++
":" ++
pad_date(Minute) ++
":" ++
pad_date(Second) ++
"Z",
http_uri:encode(S).
%% Test: > book_request:timestamp().
%% "2015-04-13T22%3A08%3A16Z"
%% List parameters
parameters(ISBN) ->
[
{"Service=AWSECommerceService"},
{"Operation=ItemLookup"},
{"ResponseGroup=Small"},
{"SearchIndex=All"},
{"IdType=ISBN"},
{"ItemId=" ++ ISBN},
{"AWSAccessKeyId=" ++ ?ACCESS_KEY},
{"AssociateTag=" ++ ?ASSOC_TAG},
{"Timestamp=" ++ timestamp()}
].
%% Test: > book_request:parameters("9780982589205").
%% [{"Service=AWSECommerceService"},
%% {"Operation=ItemLookup"},
%% {"ResponseGroup=Small"},
%% {"SearchIndex=All"},
%% {"IdType=ISBN"},
%% {"ItemId=9780982589205"},
%% {"AWSAccessKeyId=[My secret key]},
%% {"AssociateTag=[My associate tag]"},
%% {"Timestamp=2015-04-13T22%3A11%3A54Z"}]
%% Compute signature and request
%% See: http://docs.aws.amazon.com/AWSECommerceService/latest/DG/rest-signature.html
by_isbn(ISBN) ->
% Compute request
Http = "http://webservices.amazon.com/onca/xml?",
A = parameters(ISBN),
B = lists:flatten([element(1, X) ++ "&" || X <- A]),
C = string:substr(B, 1, length(B) - 1),
Request = Http ++ C,
% io:format("~nREQUEST: ~n~s~n~n", [Request]),
% Compute signature
% http://docs.aws.amazon.com/AWSECommerceService/latest/DG/rest-signature.html
D = lists:sort(A),
E = [element(1,X) ++ "&" || X <- D],
F = lists:flatten(E),
G = string:substr(F, 1, length(F) -1 ),
% io:format("STEPS 3, 4, 5 - Split and sort parameters, join with ampersands: ~n~s~n~n", [G]),
H = "GET\nwebservices.amazon.com\n/onca/xml\n" ++ G,
% io:format("STEP 6 & 7 - Prepend method; String to sign: ~n~s~n~n",[H]),
Signature = base64:encode_to_string(crypto:hmac(sha256, ?SECRET_KEY, H)),
% io:format("STEP 8 - Calculate HMAC: ~n~s~n~n",[Signature]),
% io:format("STEP 9 - uri encode HMAC"),
Request ++ "&Signature=" ++ http_uri:encode(Signature).
%% Fetch author, title, publisher via http
http_by_isbn(ISBN) ->
{ok, {_Status, _Headers, Body}} = httpc:request(by_isbn(ISBN)),
{Xml, _Rest} = xmerl_scan:string(Body),
[ #xmlText{value=Author}] = xmerl_xpath:string("//Author/text()", Xml),
[ #xmlText{value=Title}] = xmerl_xpath:string("//Title/text()", Xml),
[ #xmlText{value=Publisher}] = xmerl_xpath:string("//Manufacturer/text()", Xml),
{Author, Title, Publisher}.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment