Created
February 11, 2015 15:30
-
-
Save arnaldopereira/55ea696b74db0bbc0448 to your computer and use it in GitHub Desktop.
tornado httpclient
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# encoding: utf-8 | |
from tornado import gen | |
from tornado.httpclient import HTTPError | |
from tornado.httpclient import AsyncHTTPClient | |
from tornado.httputil import url_concat | |
from tornado.ioloop import IOLoop | |
class HTTPClient(object): | |
"""HTTP client implementation that uses tornado's AsyncHTTPClient. | |
We try and encode every body object to JSON before sending through the | |
wire, also we assume the default headers to be: {'Content-Type': 'application/json'}. | |
Typical uses should be: | |
client = HTTPClient('http://google.com', | |
default_url_params={'q':'arnaldo'}, | |
default_headers={}) | |
res = yield client.get() | |
Making a POST then a LIST request to an API: | |
client = HTTPClient('http://my-api.com/resource', | |
default_url_params={'apikey':'32e4f5ce-14b1-47ef-a5ca-dd94b918b3fd'}) | |
post_response = yield client.post({'product':'x'}) | |
list_response = yield client.list() | |
Firing 2 POSTs simultaneously: | |
client = HTTPClient('http://my-api.com/resource', | |
default_url_params={'apikey':'32e4f5ce-14b1-47ef-a5ca-dd94b918b3fd'}) | |
post_responses = yield [client.post({'product':'x'}), client.post({'product':'y'})] | |
""" | |
def __init__(self, url, default_url_params={}, default_headers={'Content-Type: application/json'}): | |
self.url = url | |
self.default_url_params = default_url_params | |
self.http_client = AsyncHTTPClient() | |
self.default_headers = default_headers | |
def _encode_body(self, body): | |
"""Convenience method that simply encodes a payload to JSON, | |
logging and raising an exception if one occurs. | |
""" | |
try: | |
encoded_body = json.dumps(body) | |
except Exception as e: | |
raise e | |
return encoded_body | |
@gen.coroutine | |
def _fetch(self, method, body=None, custom_headers=None): | |
"""Execute the request. | |
If we get an exception from AsyncHTTPClient we only raise it to the | |
caller if it's not HTTPError. Otherwise we treat the action of sending | |
the request, and of course getting a response, as a success. | |
That's intentional since 4xx and 5xx are also valid HTTP responses that | |
must be exposed to the user - and the default implementation of | |
AsyncHTTPClient.fetch raises an exception on those. | |
""" | |
headers = custom_headers or self.default_headers | |
url = url_concat(self.url, self.default_url_params) | |
body = body and self._encode_body(body) | |
try: | |
response = yield self.http_client.fetch(url, method=method, headers=headers, body=body) | |
except HTTPError as e: | |
response = e.response | |
except Exception as e: | |
raise e | |
raise gen.Return(response) | |
@gen.coroutine | |
def get(self, body=None, custom_headers=None): | |
res = yield self._fetch(method='GET', body=body, custom_headers=custom_headers) | |
raise gen.Return(res) | |
@gen.coroutine | |
def post(self, body=None, custom_headers=None): | |
res = yield self._fetch(method='POST', body=body, custom_headers=custom_headers) | |
raise gen.Return(res) | |
@gen.coroutine | |
def put(self, body=None, custom_headers=None): | |
res = yield self._fetch(method='PUT', body=body, custom_headers=custom_headers) | |
raise gen.Return(res) | |
@gen.coroutine | |
def list(self, body=None, custom_headers=None): | |
res = yield self._fetch(method='LIST', body=body, custom_headers=custom_headers) | |
raise gen.Return(res) | |
@gen.coroutine | |
def delete(self, body=None, custom_headers=None): | |
res = yield self._fetch(method='DELETE', body=body, custom_headers=custom_headers) | |
raise gen.Return(res) | |
@gen.coroutine | |
def main(): | |
client = HTTPClient('http://google.com', | |
default_url_params={'q':'arnaldo'}, | |
default_headers={}) | |
res = yield client.get() | |
print 'res:', res | |
print 'body:', res.body | |
if __name__ == '__main__': | |
IOLoop.instance().run_sync(main) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment