Fastapi: Use Pydantic BaseModel json method for test request

Created on 20 Mar 2020  路  5Comments  路  Source: tiangolo/fastapi

First check

  • [x] I used the GitHub search to find a similar issue and didn't find it.
  • [x] I searched the FastAPI documentation, with the integrated search.
  • [x] I already searched in Google "How to X in FastAPI" and didn't find any information.

Description

How can I use pydanic BaseModel json method to generate json data for my test request?

Additional context

For example I have a endpoint that accepts a Action(BaseModel) and for testing it I want to create a object of Action and use .json then pass it to client.post(json=action.json).

        request = DoActionRequest(
            game_id=self.game.id,
            action=Action(
                action_type=Action.ActionType.CAPTAIN_CALL_FOR_AN_ATTACK
            ),
            payload=None
        )
        headers = auth_header_generator(self.game.get_fd_caption())
        response = self.client.post(
            self.url, json=request.json(), headers=headers
        )

This gives me 422 http status code. but when I use the value of request.json() like
{"game_id": "1", "action": {"action_type": "call for an attack", "action_data": null}, "payload": null}
It works fine.

question

Most helpful comment

Thanks @koxudaxi for your help here! :bowing_man:

Thanks @Glyphack for reporting back and closing the issue.

All 5 comments

@Glyphack
I think request.json() returns str. But, the test client accepts dict.
Would you try request.dict()?
https://pydantic-docs.helpmanual.io/usage/exporting_models/#modeldict
https://fastapi.tiangolo.com/tutorial/testing/

I tried to pass requset.dict() for field json and got error Action object is not json serializable. I guess this happens because I have to nested messages And when I call .dict Only first one gets serialized to dict. Maybe one way is to use .dict on every class but this breaks the typing.
then I passed request.dict() to data field and it worked without error but the response had 400 status code with detail:

{'detail': 'There was an error parsing the body'}

But I found a way to make it working by using json.dumps the request.dict() and fill json filed with it.

@Glyphack
I guess json.dumps can't serialize nested Enum.
You should give a serialized request to data.

response = client.post("/", data=request.json())

I imagine your request model. This sample is a simple way.

from enum import Enum

from pydantic import BaseModel
from fastapi import FastAPI
from starlette.testclient import TestClient


class Action(BaseModel):
    class ActionType(Enum):
        CAPTAIN_CALL_FOR_AN_ATTACK = 'call for an attack'

    action_type: ActionType
    action_data: str = None


class DoActionRequest(BaseModel):
    game_id: str
    action: Action
    payload: str


app = FastAPI()


@app.post("/")
async def read_main(body: DoActionRequest):
    return body




def test_read_main():
    client = TestClient(app)
    request = DoActionRequest(
        game_id='123',
        action=Action(
            action_type=Action.ActionType.CAPTAIN_CALL_FOR_AN_ATTACK
        ),
        payload='456'
    )

    response = client.post("/", data=request.json())
    assert response.status_code == 200
    assert response.json() == {
        'game_id': '123',
        'action': {'action_type': 'call for an attack', 'action_data': None},
        'payload': '456'
    }


if __name__ == '__main__':
    test_read_main()

Hey @koxudaxi It's working in this way thank you. I'll close this issue.

Thanks @koxudaxi for your help here! :bowing_man:

Thanks @Glyphack for reporting back and closing the issue.

Was this page helpful?
0 / 5 - 0 ratings