apibee icon indicating copy to clipboard operation
apibee copied to clipboard

A dynamic api client

ApiBee

ApiBee is a dynamic rest client built on top of the excellent restkit_ library.

.. _restkit : http://github.com/benoitc/restkit

It aims to be able to handle any uris for any apis.

How it work ?

Let's say we want to fetch the json API of the great service http://www.example.com. Their api is served from http://api.example.com/1.0/::

>>> from apibee import Client
>>> api = Client('http://api.example.com/1.0/')

Now we want to get the result from http://api.example.com/1.0/users/search?q=Timy::

>>> results = api.users.search(q='Timy')

That's it !

Going further

Getting json result +++++++++++++++++++

Here::

class ExampleClient(Client):
    def process_result(self, result):
        return json.loads(result)

Now the result is a python type::

>>> api = ExampleClient("http://api.example.com/1.0/")
>>> result = api.user.search(q="timy")

Adding query automatically ++++++++++++++++++++++++++

Sometimes some api are a bit tricky. And we need to build a custom client to match thoses.

Previously, the version of the api was part of the resource but what if we have to specify it for each request::

http://api.example.com/user/search?v=1.0&q=Timy

We can specify one or more params which will be automatically add to the query::

class ExampleClient(Client):
    def set_persistent_query(**args):
        self._persistent_query = args

    def build_query(self, response, query):
        query.update(self._persistent_query)
        return response, query

>>> api = ExampleClient('http://api.example.com')
>>> api.set_persistent_query(v="1.0")

Customize resources +++++++++++++++++++

Some apis like Twitter add .json after the resource but before the query : https://api.twitter.com/1/search.json&q=Timy. We can do it like this::

class TwitterClient(Client):
    def set_format(self, f):
        self._format = f

    def build_query(self, response, query):
        response = "%s.%s" % (response, self._format)
        return response, query

>>> api = TwitterClient('https://api.twitter.com/1', end_resource='.json')
>>> results = api.search(q='Timy')

Raising errors ++++++++++++++

Sometimes you may have to clean up the result before send it back. You can do it by overloading the Client.process_result method.

Example:

Google's web service won't send an http error 400 if the request failed. Instead, it will send a custom result::

    http://ajax.googleapis.com/ajax/services/search/web?q=Earth%20Day

will send back::

{"responseData": null, "responseDetails": "invalid version", "responseStatus": 400}

Let's say we want to catch the error and raise an RequestFailed exception with a custom message which is in the "responseDetails" field::

    class GoogleClient(Client):
        def process_result(self, result):
            if result["responseStatus"] == 400:
                raise RequestFailed(result['responseDetails'])
            return result

That's it ! Don't forget to return the result at the end of the process_result method.

    >>> api = GoogleClient('http://ajax.googleapis.com/ajax/services')
    >>> api.search.web(q="toto")
    Traceback (most recent call last):
    ...
    RequestFailed: invalid version