Skip to content

Instantly share code, notes, and snippets.

@tchen
Created May 31, 2017 04:59
Show Gist options
  • Save tchen/6366fbfbe73c0d9adfe17d934ac1b3bd to your computer and use it in GitHub Desktop.
Save tchen/6366fbfbe73c0d9adfe17d934ac1b3bd to your computer and use it in GitHub Desktop.
Tornado JSON request body
# An example tornado request handler that handles both JSON POST request
# bodies and x-www-form-urlencoded POST bodies.
#
# The benefit of JSON request bodies are more complicated and potentially
# nested dict and list data types.
#
# One drawback to JSON request bodies is that arguments can come in
# different types, so handlers will need to perform additional checks.
# With x-www-form-urlencoded fields, all argument values are strings, if
# they exist.
import tornado.escape
import tornado.ioloop
import tornado.web
class JSONBaseHandler(tornado.web.RequestHandler):
def prepare(self):
super(JSONBaseHandler, self).prepare()
self.json_data = None
if self.request.body:
try:
self.json_data = tornado.escape.json_decode(self.request.body)
except ValueError:
# TODO: handle the error
pass
def get_argument(self, arg, default=None):
# TODO: there's more arguments in the default get_argument() call
# TODO: handle other method types
if self.request.method in ['POST', 'PUT'] and self.json_data:
return self.json_data.get(arg, default)
else:
return super(JSONBaseHandler, self).get_argument(arg, default)
def post(self):
print self.get_argument('hello', None)
def get(self):
self.write("Hello, world")
def make_app():
return tornado.web.Application([
(r"/", JSONBaseHandler),
])
if __name__ == "__main__":
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
# Test with:
# curl http://localhost:8888 --data '{"hello": "world"}'
@thekie
Copy link

thekie commented Mar 18, 2019

Here is another apporach. Instead of overriding get_argument(which is just one way of retrieving the arguments of a request) how about enriching the request:

    def prepare(self):
        super(JSONBaseHandler, self).prepare()
        if self.request.headers.get('Content-Type') == 'application/json; charset=utf-8':
            json = tornado.escape.json_decode(self.request.body)
            for key, value in json.items():
                if type(value) is list:
                    self.request.arguments.setdefault(key, []).extend(value)
                elif type(value) is dict:
                    self.request.arguments[key] = value
                else:
                    self.request.arguments.setdefault(key, []).extend([value])

@tchen
Copy link
Author

tchen commented Nov 27, 2020

Thanks for the suggestions. Didn't see your comment until I browsed my own gist a whole 1.5 years later. :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment