blog.humaneguitarist.org

getting started with the Summon API and Python

[Thu, 04 Sep 2014 16:51:02 +0000]
Why is it I always think clearest when I'm home sick? That's a post for another time (workplace, structure without structure, working without having showered, etc.) ... But for now, I'm working on something at work that requires we connect to the ProQuest Summon API [http://api.summon.serialssolutions.com/help/api/home]. Now, the API documentation is far better than I've seen from some other vendors and they even have some code libraries [http://api.summon.serialssolutions.com/help/api/code] but I still think that it's still far too common for people who write code and share it to kind of think that's sufficient. I don't think it is. Because I'm lazy ... in a good way, no doubt. I tend to move on when I don't see example uses of the code because I'm not sure it's really saving me time in the end ... and isn't that the ultimate point of code libraries? Anyway, I need a PHP library to connect to Summon but Googled for a Python one, thinking that if I liked it and it was easy to grasp, I could just translate it to PHP. Luckily, I found one here: https://gist.github.com/lawlesst/1070641 [https://gist.github.com/lawlesst/1070641]. I tweaked it to my tastes and changed the Host path to be for version 2.0 of the Summon API. Aside from renaming and rearranging some things, I added a few parameters and changed the function to run a search from start to finish. I need to test it more and think about a few more things (timeouts, etc.) but for now, I'm seeing results back so things are progressing. The parameters I added are the API ID and Key themselves as well as offset and limit options. The "doctype" parameter let's one choose "xml" (default) or "json". Initially, I had a "method" parameter that could be set to "search" (default") or "image" but I am getting 404's from the Summon Cover Image API [http://api.summon.serialssolutions.com/help/api/covers], so I dropped that for now. Here's the code below, if anyone's interested. I'll post a PHP version when that's done. ##### def search_summon_v2(query, api_id, api_key, offset=0, limit=10, sort=False, doctype="xml"): """ Returns results from Summon API. ... total rip-off of code found at https://gist.github.com/lawlesst/1070641. :-] """ # import modules. import base64, hashlib, hmac, urllib2 from datetime import datetime from urllib import unquote_plus # set API host and path. host = "api.summon.serialssolutions.com" path = "/2.0.0/search" # sort and encode $query. ##offset = offset + 1 #Summon starts at "1" not "0". # Actually, I think I was wrong about this so I commented-out the line. query = "s.q=" + query + ("&s.pn=%d&s.ps=%d") %(offset, limit) if sort != False: query = query + "&s.sort=PublicationDate:desc" query_sorted = "&".join(sorted(query.split("&"))) query_encoded = unquote_plus(query_sorted) # create request headers. if doctype not in ["xml", "json"]: doctype = "xml" accept = "application/%s" %doctype date = datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT") id_string = "\n".join([accept, date, host, path, query_encoded, ""]) digest = base64.encodestring(hmac.new(api_key, unicode(id_string), hashlib.sha1).digest()) authorization = "Summon " + api_id + ";" + digest headers = {"Accept":accept, "x-summon-date":date, "Host":host, "Authorization":authorization} # send search to API; return results. url = "http://%s%s?%s" % (host, path, query) request = urllib2.Request(url=url, headers=headers) results = urllib2.urlopen(request).read() return results ######################### ##### EXAMPLE USAGE ##### ######################### # get API ID and Key strings from external file (no peeking!). import summon_credentials as smn # send sample query and print results. query = "kittens" ##query = "kittens&s.dym=true" #example of passing more Summon parameters via the query string. results = search_summon_v2(query, smn.api_id, smn.api_key, limit=1, doctype="json") print results ... Update, later in the day: I just noticed that line 33 which originally read as this: authorization = ("Summon " + api_id + ";" + digest).replace("\n", "") was overkill because the line breaks already got Base64 encoded, so there should be none to replace.