1

I have a test case where I am testing a POST service using pytest hosted with FastAPI Uvicorn. However the response is getting responded with status code 307. But this doesn't happen on actual webservice is tested through a browser or curl. What is happening here?

from fastapi.testclient import TestClient
from src.main import app
import json

client = TestClient(app)

def test_get_confidence_ws():
    data = {
        "acc_id": 1234567801,
        "remoteIp": "127.255.255.255",
        "userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:104.0) Gecko/20100101 Firefox/104.0"
    }
    response = client.post("/confidence", json=json.dumps(data))
    assert response.status_code == 200

Test response

>       assert response.status_code == 200
E       assert 307 == 200
E        +  where 307 = <Response [307]>.status_code

EDIT:

Actual endpoint that is tested:

@app.post("/confidence/")
def get_confidence(json: LoginClassifierSchema):
    ...
    response = {
           "key" : "value"
        }
    return response
5
  • 1
    Is your endpoint defined as /confidence/ and not /confidence? Since you didn't include the FastAPI code, it's hard to say - but that's usually the reason. Commented Sep 27, 2022 at 11:53
  • Yes. However if I drop the / in the end, the response code changes to 422 Commented Sep 27, 2022 at 11:54
  • Added the actual endpoint @MatsLindh Commented Sep 27, 2022 at 11:58
  • 1
    @MatsLindh pointed out the reason for the 307 - if you define the endpoint with trailing slash and try to POST to it without slash, you will get 307 with Location: header. The 422 is probably due to your POST data not validating with the LoginClassifierSchema model. Commented Sep 27, 2022 at 12:09
  • 1
    The body of the 422 error response will contain the error message telling you exactly which required value is missing. Commented Sep 27, 2022 at 12:22

1 Answer 1

1

Thanks @MatsLindh and @Vaizki for your responses. The problem was indeed with / and Validation. I will explain in detail so as this benefits the community.

1>If you are getting redirected to 307 this is indeed you have an extra '/' in the endpoint.

2>If you are getting 422 it is most likely a parsing issue. In my case I was using pydantic and though pydantic models are dictionary like, they are not dictionaries. Therefore to get the exact keys you need to convert the data at endpoint to a dictionary by calling data.dict(). eg.,

@app.post("/confidence")
def get_confidence(data: LoginClassifierSchema):
     data = data.dict()
     ...
     ...
     return JSONResponse({"key":"val"}, status_code=200)

In order to understand at an early stage it is a validation issue, add a exception handler method to your app class with endpoints.

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
        """
        This catches the schema validation error made during the call
        """
        validation_err = {"exception": "RequestValidationError: unable to parse input, " + str(exc)}
        return JSONResponse(validation_err, status_code=400)
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.