[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