Search code examples
pythonunit-testingpytesthttp-postfastapi

FastAPI POST Pydantic method unit testing redirecting status_code 307 instead of 200


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

Solution

  • 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)