0

I'm getting this error while trying to accept a pedantic model. After debugging for quite some time I believe the problem is with accepting CodeCreate

Pydantic model

class BaseCode(BaseModel):
    index: Optional[int] = Field(None)
    email: EmailStr
    gen_time: datetime
    expire_time: datetime


class CodeCreate(BaseCode):
    code: int
    used_time: Optional[datetime] = Field(None)

    class Config:
        orm_mode = True

class Message(BaseModel):
    message: str

Code ORM

class Code(Base):
    __tablename__ = 'code'

    index = Column(Integer, primary_key=True, autoincrement=True)
    code = Column(Integer)
    email = Column(String, ForeignKey('user.email'))
    gen_time = Column(DateTime)
    expire_time = Column(DateTime)
    used_time = Column(DateTime, nullable=True)

Handler

@app.post('/verify-code', response_model=schemas.Message, responses={404: {"model": schemas.Message}, 406: {"model": schemas.Message}})
async def verify_code(code: schemas.CodeCreate, response: Response, device_name: str = Body(..., embed=True), db=Depends(get_db)):

    result = crud.verify_and_insert_code(db=db, code=code)
    if result == 'matched':
        response.status_code = status.HTTP_202_ACCEPTED
        return crud.start_new_session(db=db, session=schemas.Session(session_id='1234', start_time=datetime.now(), email=code.email, device_name=device_name))
    elif result == 'not-matched':
        response.status_code = status.HTTP_200_OK
    elif result == 'expire':
        response.status_code = status.HTTP_406_NOT_ACCEPTABLE
    elif result == 'invalid':
        response.status_code = status.HTTP_404_NOT_FOUND

    return schemas.Message(message="Item not found")

Body of request from the client

{
  "code": {
    "index": 0,
    "email": "user@example.com",
    "gen_time": "2022-01-24T16:38:12.612Z",
    "expire_time": "2022-01-24T16:38:12.612Z",
    "code": 0,
    "used_time": "2022-01-24T16:38:12.612Z"
  },
  "device_name": "string"
}

Response body for 422

{
  "detail": [
    {
      "loc": [
        "body",
        "code",
        "email"
      ],
      "msg": "field required",
      "type": "value_error.missing"
    },
    {
      "loc": [
        "body",
        "code",
        "gen_time"
      ],
      "msg": "field required",
      "type": "value_error.missing"
    },
    {
      "loc": [
        "body",
        "code",
        "expire_time"
      ],
      "msg": "field required",
      "type": "value_error.missing"
    },
    {
      "loc": [
        "body",
        "code",
        "code"
      ],
      "msg": "field required",
      "type": "value_error.missing"
    }
  ]
}

Temporary Solution

Removing this ORM confirmation code from Pydantic model solves the issue. I believe there might be a clash between CodeCreate pydantic model and Code ORM model, but I don't know how to resolve it.

class Config:
    orm_mode = True
ASAD HAMEED
  • 2,296
  • 1
  • 20
  • 36
  • 3
    The body of FastAPIs 422 response contains an error message telling you exactly which part of your request doesn't match the expected format. – MatsLindh Jan 24 '22 at 11:07
  • Future readers may find [this answer](https://stackoverflow.com/a/70636163/17865804) helpful as well. – Chris Mar 14 '23 at 12:40

4 Answers4

3

The 422 Unprocessable Entity error because of ContentType is incorrect. The FastAPI/Pydantic need ContentType = application/json to parse request body.

Are you sure your POST request has ContentType header is application/json?

If not add it!

0

According to MDN here, a 422 Unprocessable Entity means that the information of the request could not be processed.

In this case, the most likely problem is that the data of the POST request that is sent does not match with the Pydantic model.

Make sure the data that is sent is in the correct format.

0

Just as stated above by Brian Law, your request body is in the form of Code, which is not a pydantic model, but a database one.

When you send the POST request, the body should match up with CodeCreate, not Code.

Brian
  • 388
  • 3
  • 8
0

Found the solution after debugging for quite a while.

The ORM configured pedantic model can't be used to receive requests from the client.

In my case, I had to create another class that extends the CodeCreate class add ORM configuration to that class and use CodeCreate for body from the client.

class BaseCode(BaseModel):
    index: Optional[int] = Field(None)
    email: EmailStr
    gen_time: datetime
    expire_time: datetime


class CodeCreate(BaseCode):
    code: int
    used_time: Optional[datetime] = Field(None)

    
class Code(CodeCreate):

    class Config:
            orm_mode = True

Post request

@app.post('/verify-code')
async def verify_code(code: schemas.CodeCreate):
    return 'success'
ASAD HAMEED
  • 2,296
  • 1
  • 20
  • 36