pythonresttornado

How to send a JSON file using a http POST with Tornado?


I'm trying to write a REST service: the client with an http POST request send a JSON to the server, and the server respond with an id.

Basing on this post the code should look like this:

server.py

import tornado.httpclient
from datetime import date
import tornado.ioloop
import tornado.web
from tornado.escape import json_decode, json_encode, url_unescape

class Variazione(tornado.web.RequestHandler):

    def post(self):
        print json_decode(self.request.body)
        response = {'id': '12345'}
        self.write(response)
        tornado.ioloop.IOLoop.instance().stop()

application = tornado.web.Application([
    (r"/variazione", Variazione)
])

if __name__ == "__main__":
    application.listen(8889)
    tornado.ioloop.IOLoop.instance().start()

client.py

import tornado.httpclient
import json
from tornado.escape import json_decode, json_encode
from tornado import gen
import tornado.options

def read_json():
    with open('articoli.json') as json_file:
        json_data = json.load(json_file)
        print json_data
        return json_data

@tornado.gen.coroutine  
def json_fetch(http_client, body):
    response = yield http_client.fetch("http://localhost:8889/variazione", method='POST', body=body)
    raise gen.Return(response)

@tornado.gen.coroutine
def request(http_client):
    data = read_json()
    body = json_encode(data)
    http_response = yield json_fetch(http_client, body)
    print http_response.body


if __name__ == "__main__":
    tornado.options.parse_command_line()
    http_client = tornado.httpclient.AsyncHTTPClient()
    request(http_client)

But nothing happens, the server don't receive anything and no error occur.

Where am I doing wrong?


Solution

  • ##server.py

    First of all, do not stop IOLoop in handler, unless you know what you are doing - in your example after the first request, the application will exit.

    So it should look like:

    import tornado.ioloop
    import tornado.web
    from tornado.escape import json_decode, json_encode
    
    class Variazione(tornado.web.RequestHandler):
    
        def post(self):
            print json_decode(self.request.body)
            response = {'id': '12345'}
            self.write(response)
    
    application = tornado.web.Application([
        (r"/variazione", Variazione)
    ])
    
    if __name__ == "__main__":
        application.listen(8889)
        tornado.ioloop.IOLoop.instance().start()
    

    ##client.py

    The request function is a coroutine, so it cannot be called as is. It requires a running IOLoop. The simplest solution in your example is to use run_sync, which will run ioloop, schedule coroutine and will wait until it finished than stop ioloop.

    For brevity I've removed part read_json(not related to problem) and move http_client to request.

    import tornado.httpclient
    import json
    from tornado.escape import json_decode, json_encode
    from tornado import gen
    import tornado.options
    
    
    @tornado.gen.coroutine  
    def json_fetch(http_client, body):
        response = yield http_client.fetch("http://localhost:8889/variazione", method='POST', body=body)
        raise gen.Return(response)
    
    @tornado.gen.coroutine
    def request():
        body = '{"test_json": "ok"}'
        http_client = tornado.httpclient.AsyncHTTPClient()
        http_response = yield json_fetch(http_client, body)
        print http_response.body
    
    
    if __name__ == "__main__":
        tornado.options.parse_command_line()
        tornado.ioloop.IOLoop.instance().run_sync(request)