positional argument error when trying to send a post request

Question:

I am trying to send a post request to a python backend running on a fast API server. The current method I am using below throws error test() takes 0 positional arguments but 1 was given but I haven’t passed any arguments to the function test. Why is this happening and how can I fix it? Thanks in advance.

import requests

data = {"foo": "bar"}

r = requests.post("http://127.0.0.1:8000/test", json = data)

print(r.text)
import requests
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.route('/test', methods=['POST'])
def test(request):
    print(request.form['foo'])
    return 'thisIsResponse'

EDIT: as per John Gordon’s answer I updated my code by assigning a positional argument to the test function now I get error TypeError: 'method' object is not subscriptable

Stack trace:

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/uvicorn/protocols/http/httptools_impl.py", line 375, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "/usr/lib/python3/dist-packages/uvicorn/middleware/proxy_headers.py", line 75, in __call__
    return await self.app(scope, receive, send)
  File "/home/spree/.local/lib/python3.10/site-packages/fastapi/applications.py", line 271, in __call__
    await super().__call__(scope, receive, send)
  File "/home/spree/.local/lib/python3.10/site-packages/starlette/applications.py", line 118, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/home/spree/.local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 184, in __call__
    raise exc
  File "/home/spree/.local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/home/spree/.local/lib/python3.10/site-packages/starlette/middleware/cors.py", line 84, in __call__
    await self.app(scope, receive, send)
  File "/home/spree/.local/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/home/spree/.local/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/home/spree/.local/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/home/spree/.local/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/home/spree/.local/lib/python3.10/site-packages/starlette/routing.py", line 706, in __call__
    await route.handle(scope, receive, send)
  File "/home/spree/.local/lib/python3.10/site-packages/starlette/routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "/home/spree/.local/lib/python3.10/site-packages/starlette/routing.py", line 66, in app
    response = await func(request)
  File "/home/spree/spreeTv/./ods_info.py", line 30, in test
    print(request.form['foo'])
TypeError: 'method' object is not subscriptable
Asked By: seriously

||

Answers:

but I haven’t passed any arguments to the function test

You aren’t calling test() directly; the FastAPI framework calls it for you, automatically, when a matching web request is received.

And when it does, it passes one argument. So the error is that you’ve defined test() to accept no arguments.

Change your definition to this:

def test(request):

(… where did you think request.form came from?)

Answered By: John Gordon

EDITED

Here’s a canonical way to get request body as any valid JSON in FastAPI.

If you want to stick to the current solution, there are two things to be changed:

  • you’re sending a JSON payload, not form data – use request.json() to get it
  • however, request.json() returns a coroutine, so to use it, I’d recommend to mark your function as async (more details here)
@app.route('/test', methods=['POST'])
async def test(request):
    print(await request.json())

P.S.
Just a note: FastAPI relies on type annotations to determine which arguments to pass. So if you need request variable to be an actual request object, just let the framework know about this:) Though in this case it will pass a request object anyway.

from fastapi import Request

@app.route('/test', methods=['POST'])
def test(request: Request):
    ...
Answered By: Oleh Rybalchenko
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.