Search code examples
pythontornadohttpresponse

How to send integer in POST to Tornado's AsyncHTTPTestCase.fetch()?


I'm using python's Tornado framework to test my HTTP POST endpoint. To do this, I'm using the fetch method.

    data = urllib.urlencode({
        'integer_arg': 1,
        'string_arg': 'hello'
    })

    resp = AsyncHTTPTestCase.fetch('/endpoint', 
                                   method='POST',
                                   headers={'h1': 'H1', 
                                            'h2': 'H2',
                                            'Content-Type': 'application/json'}, 
                                   body=data)

When I do this, the endpoint receives integer_arg as the string "1" even though I want it to receive it as an integer. This is understandable because urllib.urlencode converts it to a string. So how can I ensure it receives an integer? Just eliminating the call to urllib.urlencode doesn't work.

By the way, when I hit the same endpoint with a naked curl call as shown below, the endpoint properly receives integer_arg as the integer 1.

curl \
--request POST \
--header "h1: H1" \
--header "h2: H2" \
--header "Content-Type: application/json" \
--data '{
    "integer_arg": 1, 
    "string_arg": "hello"
}' \
"http://localhost:8000/endpoint"

Solution

  • The body in curl is significantly different than that in AsyncHTTPClient.fetch. With python you urlencode the data in curl there is just json. So simply change urlencode with json.dumps:

    import json
    from tornado.ioloop import IOLoop
    from tornado.httpclient import AsyncHTTPClient
    from tornado.gen import coroutine
    
    @coroutine
    def main():
        client = AsyncHTTPClient()
        body = json.dumps({
            'integer_arg': 1,
            'string_arg': 'hello'
        })
        yield client.fetch(
            '/endpoint', method='POST', body=body,
             headers={'h1': 'H1',  'h2': 'H2', 'Content-Type': 'application/json'}
        )
    
    ioloop = IOLoop.instance()
    ioloop.run_sync(main)