Search code examples
fastapipydantic

Fastapi/Pydantic missing field but can't see what's missing


I have the following models:

class BaseMessage(BaseModel):
    """
    Base schema for returning a ACK/NACK response.
    """

    origin: str = settings.APP_ORIGIN_NAME
    message: str

class Success(BaseMessage):
    """
    API schema for returning a Success response.
    """

    id: str
    temp_password: Optional[str] | None

class ACK(BaseModel):
    """
    API schema for returning an ACK response.
    """

    ACK: Success

and in my POST endpoint, I have this:

@router.post(
    path="/",
    summary="register a new domain",
    description="Registers a new domain.",
    response_model=Union[ACK, NACK],
    name="domains:create-domain",
    status_code=status.HTTP_201_CREATED,
    responses={400: {"model": NACK}},
)
async def create_domain(
    domain: DomainCreate, 
) -> JSONResponse:
try:
   instance = Domains(**domain.dict(exclude_unset=True))
   instance.domain_hashed_password = get_password_hash(
       instance.domain_hashed_password
   )
   db_instance = await 
     Domains(**instance.dict(exclude_unset=True)).save()

   domain_id: str = str(db_instance.domain_id)

   success_text: str = ENDPOINT_MESSAGES["success"]
   
   try:
      ack_message = ACK(
         message=success_text,
         id=domain_id,
         temp_password=instance.domain_hashed_password,
      )

      return JSONResponse(
          status_code=status.HTTP_201_CREATED,
          content=jsonable_encoder(ack_message),
      )
   except ValidationError as exc:
      print(exc.errors())
except asyncpg.exceptions.UniqueViolationError:
   failure_text: str = ENDPOINT_MESSAGES["failure"]
   error_text: str = f"{ENDPOINT_MESSAGES['err_unique']} domain_name"
   nack_message: dict = APIResponse.nack(failure_text, error_text)

   return JSONResponse(
        status_code=status.HTTP_400_BAD_REQUEST, content=nack_message
        )

I keep getting..

ACK
  field required (type=value_error.missing)

fastapi.exceptions.ResponseValidationError: 1 validation errors:
  {'loc': ('response',), 'msg': 'none is not an allowed value', 'type': 'type_error.none.not_allowed'}

...error messages when I POST to the endpoint. It's failing when coming to ack_message, which is not clear to me why as I am providing all the fields. Well at least I think I am. I'm using my ACK model to provide a json response to the end user. I'm clearly doing something wrong. I was expecting ack_message to return:

{
  "ACK": {
    "origin": "contents of APP_ORIGIN_NAME",
    "message": "contents of success_text",
    "id": "contents of domain_id",
    "temp_password": "contents of domain_hashed_password"
  }
}

Solved.

Have solved this based on Victor's answer below. I have to change my ack_message definition to:

ack_message = ACKResponse(
        ACK={
            "message": success_text,
            "id": domain_id,
            "temp_password": unhashed_password,
        }
    )

Solution

  • Well, here I would recommend to rename your entities: ACK is your model name and the name of it's field.

    class ACK(BaseModel):
        """
        API schema for returning an ACK response.
        """
    
        ACK: Success
    

    So this line will definitely cause an error as value for ACK field was not specified.

    ack_message = ACK(
      message=success_text,
      id=domain_id,
      temp_password=instance.domain_hashed_password,
    )