PyEDS: a simple Python starter library for EBSCO's Discovery Service (EDS)

Before this little vacation I'm on started (sadly, it's almost over!), I was allowed to have access to EBSCO's Discovery Service (EDS) API and its documentation WIKI.

I sent a tiny bit of feedback on some of the things in the documentation that I think are unclear or really need correction and I'm looking to send more when I return to work.

My biggest concern was that  – and I think this is true of A LOT of API documentation – it requires a lot of reading on the user's part to figure out what means what, which almost invariably exceeds the amount of work to actually write the code to authenticate, make queries, etc.

That's to say that often working through documentation about tying a shoelace is more of a task than actually tying said shoelace.

I *think* developers really just want to start experimenting with code, so clarity and really concise language with examples are really of the utmost importance.

Speaking of examples, I also think that sample code needs to have scope in mind. What I'm getting at is that sample code for a search API shouldn't be a "soup to nuts" thing that entails authenticating, making requests, having a client-side UI/interface and displaying results, etc. That's too much. Again, I think (off the top of my head of course and with nothing more than a gut feeling) that it might be more helpful to simply show how to authenticate and make a request and show the formatting of a sample response. The other stuff – interface, UI, etc, etc. – just convolutes the code and adds noise to the basics. In fact, that confuses API usage implementation vs. the API usage itself.

Better still would be to offer small libraries in popular scripting languages that simplify the basics – again, to facilitate people playing with one's API's. The easier and more "fun" it is, the more likely I think (yeah, yeah, I know!) people are likely to really dream about incorporating the API, etc. into their applications and what-nots.

So along those lines, I've pasted a little sample Python script below that makes it really easier for me to authenticate, open a session, conduct searches, format the JSON response, and close the session. It needs work (what doesn't?) but it does what I mean for it to for now.

I probably shouldn't post a sample response since access to the EDS WIKI is for customers only, but if you aren't a customer or at least aren't interested, why are you even reading this? 🙂

#PyEDS.py

'''
This module provides a basic Python binding to EBSCO's EDS API, allowing one to:
  - authenticate with a UserID and Password,
  - open and close a session,
  - perform a search (results are returned as JSON),
  - pretty print the JSON.
 
Thanks,
Nitin Arora; nitaro74@gmail.com
____________________________________________________________________________________________________
#Usage example:
 
  import PyEDS as eds
  
  eds.authenticateUser('USERID_GOES_HERE', 'PASSWORD_GOES_HERE')
  eds.openSession('PROFILE_GOES_HERE', 'GUEST_GOES_HERE', 'ORG_GOES_HERE')
 
  #eds.authenticateFile() #alternative to using authenticateUser() and openSession()
  #uses values in JSON config file argument(default="config.json")
  
  #sample "config.json" file:
  """
  {
    "EDS_config": {
      "UserId": "USERID_GOES_HERE",
      "Password": "PASSWORD_GOES_HERE",
      "Profile": "PROFILE_GOES_HERE",
      "Guest": "GUEST_GOES_HERE",
      "Org": "ORG_GOES_HERE"
    }
  }
  """
 
  kittens = eds.advancedSearch('{"SearchCriteria":{"Queries":[{"Term":"kittens"}],"SearchMode":"smart","IncludeFacets":"y","Sort":"relevance"},"RetrievalCriteria":{"View":"brief","ResultsPerPage":10,"PageNumber":1,"Highlight":"y"},"Actions":null}')
  puppies = eds.advancedSearch('{"SearchCriteria":{"Queries":[{"Term":"puppies"}],"SearchMode":"smart","IncludeFacets":"y","Sort":"relevance"},"RetrievalCriteria":{"View":"brief","ResultsPerPage":10,"PageNumber":1,"Highlight":"y"},"Actions":null}')
  cubs = eds.basicSearch('cubs')
  piglets = eds.basicSearch('piglets', view='brief', offset=1, limit=10, order='relevance')
  
  eds.closeSession()
  
  print 'Some search results with the EDS API ...'
  print '\n"kittens" advanced search as original JSON:'
  print kittens
  print '\n"puppies" advanced search as original JSON:'
  print puppies
  print '\n"kittens" advanced search as JSON with indentation and non-ascii escaping:'
  print eds.prettyPrint(kittens)
  print '\n"cubs" and "piglets" basic searches as original JSON:'
  print cubs, piglets
  print '\nGoodbye.'
____________________________________________________________________________________________________
 
TO DO:
  - add more options to basicSearch() like "facets", "search mode", "fulltext", "thesauras", etc.
    - can't hurt! :-]
  - consider adding an authenticateIP() function that uses the IP authentication method.
  - deal with expired tokens, etc.; see: http://edswiki.ebscohost.com/API_Reference_Guide:_Appendix
'''
 
import urllib2
_EDS_ = {}
 
 
def authenticateUser(UserId, Password):
  '''Authenticates user with an EDS UserId and Password.'''
  auth_json = '{"UserId":"%s","Password":"%s","InterfaceId":"WSapi"}' %(UserId, Password)
  req = urllib2.Request(url='https://eds-api.ebscohost.com/authservice/rest/UIDAuth',
                        data=auth_json,
                        headers={'Content-Type':'application/json'})
  req_open = urllib2.urlopen(req)
  req_results = req_open.read()
  
  req_results_dictionary = eval(req_results) #convert JSON to dictionary.
  _EDS_['AuthToken'] = req_results_dictionary['AuthToken']
  _EDS_['AuthTimeout'] = req_results_dictionary['AuthTimeout']
 
 
def openSession(Profile, Guest, Org):
  '''Opens the EDS session with an EDS Profile, the Guest value ("y" or "n"), and the Org nickname.'''
  sessionOpen_json = '{"Profile":"%s","Guest":"%s","Org":"%s"}' %(Profile, Guest, Org)
  req = urllib2.Request(url='http://eds-api.ebscohost.com/edsapi/rest/CreateSession',
                        data=sessionOpen_json,
                        headers={'Content-Type':'application/json',
                        'x-authenticationToken':_EDS_['AuthToken']})
  req_open = urllib2.urlopen(req)
  req_results = req_open.read()
 
  req_results_dictionary = eval(req_results)
  _EDS_['SessionToken'] = req_results_dictionary['SessionToken'].replace('\\/', '/')
 
 
def closeSession():
  '''Closes the EDS sesssion.'''
  sessionClose_json = '{"SessionToken":"%s"}' %(_EDS_['SessionToken'])
  req = urllib2.Request(url='http://eds-api.ebscohost.com//edsapi/rest/EndSession',
                        data=sessionClose_json,
                        headers={'Content-Type':'application/json',
                        'x-authenticationToken':_EDS_['AuthToken']})
  urllib2.urlopen(req)
  
  
def authenticateFile(config_file='config.json'):
  '''Uses values in JSON config file to authenticate *and* open a session.'''
  config = open(config_file, 'r').read()
  config = eval(config)
  config = config['EDS_config']
  authenticateUser(config['UserId'], config['Password'])
  openSession(config['Profile'], config['Guest'], config['Org'])
 
 
def basicSearch(query, view='brief', offset=1, limit=10, order='relevance'):
  '''Returns search results using basic arguments.'''
  search_json = '''{"SearchCriteria":{"Queries":[{"Term":"%s"}],"SearchMode":"smart","IncludeFacets":"n","Sort":"%s"},
                   "RetrievalCriteria":{"View":"%s","ResultsPerPage":%d,"PageNumber":%d,"Highlight":"n"},"Actions":null}
                   ''' %(query, order, view, limit, offset)
  return advancedSearch(search_json)
 
         
def advancedSearch(search_json):
  '''Returns search results using the full EDS search syntax (JSON).'''
  req = urllib2.Request(url='http://eds-api.ebscohost.com/edsapi/rest/Search',
                        data=search_json, headers={'Content-Type':'application/json',
                        'x-authenticationToken':_EDS_['AuthToken'],
                        'x-sessionToken':_EDS_['SessionToken']})
  req_open = urllib2.urlopen(req)
  req_results = req_open.read()
  return req_results
 
 
def prettyPrint(json_string):
  '''Returns a pretty-printed, UTF-8 encoded JSON string with escaped non-ASCII characters.'''
  import json
  dictionary = json.loads(json_string, encoding='utf=8')
  return json.dumps(dictionary, ensure_ascii=True, indent=2, encoding='utf-8')
 
 
#fin
--------------

Related Content:

2 Comments

  1. Christian

    I don't really understand your blog-post.
    Is PyEDS writte by you? Or do you just report about it here?

    Is there a project website? Is there a source repository? I can not find anything on GitHub or PyPi.

    thanks for your work

    Reply
    1. nitin (Post author)

      Hi Christian,

      Sorry about the confusion.

      Yes, PyEDS was something I wrote. All the posts about it are here: http://blog.humaneguitarist.org/tag/pyeds/.
      I don't put code on GitHub, etc. I just keep it all here.

      You might be more interested in the "official" EDS wrapper recently created by EBSCO: https://pypi.python.org/pypi/ebscopy/.

      Hope that helps,
      Nitin

      Reply

Leave a Comment

Your email address will not be published. Required fields are marked *


*