user14701487
user14701487

Reputation:

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?

Upvotes: 0

Views: 4900

Answers (1)

furas
furas

Reputation: 142711

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)

Upvotes: 1

Related Questions