Reputation: 329
After the release of Tornado 5, we are unable to use synchronous HTTPClient while IOLoop is running. We would have to use AsyncHTTPClient instead.
Therefore, can someone help me out by showing me how can I make synchronous API calls using AsyncHTTPClient in Tornado(Python web framework), which uses async and await instead of the old traditional methods of yield.
I tried to implement it this way, and have been getting multiple errors.
class IndexHandler(tornado.web.RequestHandler):
async def get_result(self, query):
client = tornado.httpclient.AsyncHTTPClient()
return await client.fetch("https://pokeapi.co/api/v2/pokemon/" + urllib.parse.urlencode(query))
def get(self):
q = self.get_argument('q')
query = {'q': q}
loop = asyncio.get_event_loop()
response = loop.run_until_complete(self.get_result(query))
loop.close()
#response = client.fetch("https://pokeapi.co/api/v2/pokemon/" + urllib.parse.urlencode(query))
#self.on_response(response)
if response == "Not Found":
self.write("Invalid Input")
response_data = json.loads(response.body)
pikachu_name = response_data['name']
pikachu_order = response_data['order']
self.write("""
Pickachu Name: %s <br>
Pickachu Order: %d <br>
""" %(pikachu_name, pikachu_order))
But unfortunately, I've been getting a lot of errors.
[E 200410 02:40:48 web:1792] Uncaught exception GET /?q=pikachu (::1)
HTTPServerRequest(protocol='http', host='localhost:8000', method='GET', uri='/?q=pikachu', version='HTTP/1.1', remote_ip='::1')
Traceback (most recent call last):
File "C:\Python\Python37\lib\site-packages\tornado\web.py", line 1701, in _execute
result = method(*self.path_args, **self.path_kwargs)
File "C:\Users\Bagga\Documents\tornado\Tweet Rate\handlers.py", line 25, in get
response = loop.run_until_complete(self.get_result(query))
File "C:\Python\Python37\lib\asyncio\base_events.py", line 571, in run_until_complete
self.run_forever()
File "C:\Python\Python37\lib\asyncio\base_events.py", line 526, in run_forever
raise RuntimeError('This event loop is already running')
RuntimeError: This event loop is already running
[E 200410 02:40:48 web:2250] 500 GET /?q=pikachu (::1) 3.33ms
[E 200410 02:40:49 base_events:1608] Task exception was never retrieved
future: <Task finished coro=<IndexHandler.get_result() done, defined at C:\Users\Bagga\Documents\tornado\Tweet Rate\handlers.py:16> exception=HTTP 404: Not Found>
Traceback (most recent call last):
File "C:\Users\Bagga\Documents\tornado\Tweet Rate\handlers.py", line 18, in get_result
return await client.fetch("https://pokeapi.co/api/v2/pokemon/" + urllib.parse.urlencode(query))
tornado.httpclient.HTTPClientError: HTTP 404: Not Found
Upvotes: 0
Views: 656
Reputation: 2789
I think there's some confusion regarding what a synchronous
request is; a synchronous request blocks
program execution (and therefore the whole IOLoop
) before it can return
a result; this is generally not what you want.
An asynchronous
request returns before it is finished; it returns placeholder objects (Futures
) which are usually transformed into their result with the await
or yield
keywords.
What I think you are looking for is a way to wait for the request to the API to complete, which as mentioned above is done with await or yield.
class IndexHandler(tornado.web.RequestHandler):
async def get_result(self, query):
client = tornado.httpclient.AsyncHTTPClient()
response = await client.fetch("https://pokeapi.co/api/v2/pokemon/" + urllib.parse.urlencode(query))
return response.body
async def get(self):
q = self.get_argument('q')
query = {'q': q}
response = await self.get_result(query)
if response == b"Not Found":
self.write("Invalid Input")
else:
response_data = json.loads(response.body)
pikachu_name = response_data['name']
...
Notice the
async def get(self):
and the
response = await self.get_result(query)
bits.
Upvotes: 0