Search code examples
pythonaiohttp

aiohttp.web post method get params


I'm trying to make an endpoint that takes parameters, this is my code:

from aiohttp import web

routes = web.RouteTableDef()

@routes.post('/test')
async def test(request):
    print(request.query)
    print(await resp.json())
    return web.Response('Testing...')

app = web.Application()
app.add_routes(routes)

if __name__ == '__main__':
    web.run_app(app)

When I try with requests in another terminal:

import requests

requests.post('http://localhost:8080/test', data={'param1': 'value1'})

It outputs:

<MultiDictProxy()>
Error handling request
Traceback (most recent call last):
  File "C:\Users\kwiecinski\Desktop\python\SETUP\venv\lib\site-packages\aiohttp\web_protocol.py", line 418, in start
    resp = await task
  File "C:\Users\kwiecinski\Desktop\python\SETUP\venv\lib\site-packages\aiohttp\web_app.py", line 458, in _handle
    resp = await handler(request)
  File "main.py", line 69, in send_message
    print(await request.json())
  File "C:\Users\kwiecinski\Desktop\python\SETUP\venv\lib\site-packages\aiohttp\web_request.py", line 584, in json
    return loads(body)
  File "C:\Users\kwiecinski\AppData\Local\Programs\Python\Python38-32\lib\json\__init__.py", line 357, in loads
    return _default_decoder.decode(s)
  File "C:\Users\kwiecinski\AppData\Local\Programs\Python\Python38-32\lib\json\decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "C:\Users\kwiecinski\AppData\Local\Programs\Python\Python38-32\lib\json\decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

It just doesn't work, what's the attribute to get the data attribute from when I make the request?


Solution

  • Your server expects JSON data.

    And requests has to use json= instead of data= to send it as JSON

    import requests
    
    requests.post('http://localhost:8080/test', json={'param1': 'value1'})
    

    or it would have to manually convert dictionary to json string using json.dumps()

    And eventually it would have to add header 'Content-Type: application/json' but not all servers need it.

    import requests
    import json
    
    requests.post('http://localhost:8080/test', 
                  data=json.dumps({'param1': 'value1'}), 
                  headers={'Content-Type': 'application/json'})
    

    EDIT:

    I never used aiohttp so I had to read documentation and test in on some code.

    BTW: I found out that it can't use at the same time: content.read(), text(), post(), json(), multiparts() because they all read from the same stream (not get from variable) and after first read this stream is empty and other function has nothing to read. And this is why I had to comment BODY, POST, JSON to test code for FILES.

    It is what I created:

    server.py

    from aiohttp import web
    
    routes = web.RouteTableDef()
    
    @routes.post('/test')
    async def test(request):
        print('\n--- request ---\n')
    
        # ----------------------------------------------------------------------
    
        print('ARGS string:', request.query_string)  # arguments in URL as string
        print('ARGS       :', request.query)         # arguments in URL as dictionary
    
        # ----------------------------------------------------------------------
    
        # >> it can't use at the same time: `content.read()`, `text()`, `post()`, `json()`, `multiparts()` 
        # >> because they all read from the same stream (not get from variable) 
        # >> and after first read this stream is empty
    
        # ----------------------------------------------------------------------
    
        #print('BODY bytes :', await request.content.read())  # body as bytes  (post data as bytes, json as bytes)
        #print('BODY string:', await request.text())          # body as string (post data as string, json as string)
    
        # ----------------------------------------------------------------------
    
        #print('POST       :', await request.post())         # POST data
    
        # ----------------------------------------------------------------------
    
        #try:
        #    print('JSON:', await request.json())  # json data as dictionary/list
        #except Exception as ex:
        #    print('JSON: ERROR:', ex)
    
        # ----------------------------------------------------------------------
    
        try:
            #print('MULTIPART:', await request.multipart())  # files and forms
            reader = await request.multipart()
            print('MULTIPART:', reader)
            while True:
                part = await reader.next()
                if part is None: 
                    break
                print('filename:', part.filename)
                print('>>> start <<<')
                print(await part.text())
                print('>>> end <<<')
        except Exception as ex:
            print('MULTIPART: ERROR:', ex)
    
        # ----------------------------------------------------------------------
    
        return web.Response(text='Testing...')
    
    app = web.Application()
    app.add_routes(routes)
    
    if __name__ == '__main__':
        web.run_app(app)
    

    client.py

    import requests
    import json
    
    # --- JSON ---
    
    
    r = requests.post('http://0.0.0.0:8080/test', json={'param1': 'value1'})
    print(r.text)
    
    # --- JSON ---
    
    r = requests.post('http://0.0.0.0:8080/test', 
                      data=json.dumps({'param1': 'value1'}),
                      headers={'Content-Type': 'application/json'},
                     )
    print(r.text)
    
    # --- POST data ---
    
    r = requests.post('http://0.0.0.0:8080/test', data={'param1': 'value1'})
    print(r.text)
    
    # --- URL data ---
    
    r = requests.post('http://0.0.0.0:8080/test', params={'param1': 'value1'})
    print(r.text)
    
    # --- FILES ---
    
    r = requests.post('http://0.0.0.0:8080/test', files=[('file', open('client.py'))])
    print(r.text)