[tornado] Async handlers, code refactor
Let's start with sync implementation:
import json
from tornado import options
from tornado.ioloop import IOLoop
from tornado.web import RequestHandler, Application
from tornado.httpclient import HTTPClient, HTTPError
class FBHandler(RequestHandler):
FB_GRAPH_ME_URL = 'https://graph.facebook.com/me?fields=id&access_token={fb_token}'
def get(self):
fb_id = self.get_argument('fb_id')
fb_token = self.get_argument('fb_token')
url = self.FB_GRAPH_ME_URL.format(fb_token=fb_token)
http_client = HTTPClient()
try:
response = http_client.fetch(request=url, method='GET')
if json.loads(response.body).get('id') == fb_id:
self.write('Ok')
return
except HTTPError:
pass
self.write('Fail')
if __name__ == '__main__':
options.parse_command_line()
application = Application(
handlers=[
(r'/', FBHandler),
],
debug=True,
)
application.listen(8000)
IOLoop.instance().start()
Make it async:
import json
from tornado import options
from tornado.ioloop import IOLoop
from tornado.web import RequestHandler, Application, asynchronous
from tornado.httpclient import AsyncHTTPClient, HTTPError
class FBHandler(RequestHandler):
FB_GRAPH_ME_URL = 'https://graph.facebook.com/me?fields=id&access_token={fb_token}'
@asynchronous
def get(self):
self.fb_id = self.get_argument('fb_id')
fb_token = self.get_argument('fb_token')
url = self.FB_GRAPH_ME_URL.format(fb_token=fb_token)
http_client = AsyncHTTPClient()
try:
response = http_client.fetch(
request=url, method='GET', callback=self.on_fetch)
except HTTPError:
self.write('Fail')
def on_fetch(self, response):
if json.loads(response.body).get('id') == self.fb_id:
self.write('Ok')
else:
self.write('Fail')
self.finish()
...
Add gen sugar:
import json
from tornado import options, gen
from tornado.ioloop import IOLoop
from tornado.web import RequestHandler, Application
from tornado.httpclient import AsyncHTTPClient, HTTPError
class FBHandler(RequestHandler):
FB_GRAPH_ME_URL = 'https://graph.facebook.com/me?fields=id&access_token={fb_token}'
@gen.coroutine
def get(self):
fb_id = self.get_argument('fb_id')
fb_token = self.get_argument('fb_token')
url = self.FB_GRAPH_ME_URL.format(fb_token=fb_token)
http_client = AsyncHTTPClient()
try:
response = yield http_client.fetch(request=url, method='GET')
if json.loads(response.body).get('id') == fb_id:
self.write('Ok')
return
self.write('Fail')
except HTTPError:
pass
self.write('Fail')
...
Hold handlers as simple as possible:
import json
from tornado import options, gen
from tornado.ioloop import IOLoop
from tornado.web import RequestHandler, Application
from tornado.httpclient import AsyncHTTPClient, HTTPError
class FBHandler(RequestHandler):
@gen.coroutine
def get(self):
try:
fb_id = self.get_argument('fb_id')
fb_token = self.get_argument('fb_token')
yield self.validate(fb_id=fb_id, fb_token=fb_token)
self.write('Ok')
except Exception:
self.write('Fail')
@gen.coroutine
def validate(self, fb_id, fb_token):
FB_GRAPH_ME_URL = 'https://graph.facebook.com/me?fields=id&access_token={fb_token}'
url = FB_GRAPH_ME_URL.format(fb_token=fb_token)
http_client = AsyncHTTPClient()
response = yield http_client.fetch(request=url, method='GET')
assert json.loads(response.body).get('id') == fb_id
raise gen.Return(True)
...
Licensed under CC BY-SA 3.0