'FastAPI - Using nested model gives JSON serialization error

I'm trying to use nested models in a POST call. The goal is to create a user in my Keycloak instance with an API, so I have created following the documentation the model that I need.

When I try to create the user with Postman using my API, fastAPI gives me the following error:

Object of type Attributes is not JSON serializable

The code is the following:

user.py

from pydantic import BaseModel


# TODO Error: Object of type Attributes is not JSON serializable.
class Attributes(BaseModel):
    locale: str
    phoneNumber: str

    class Config:
        orm_mode = True


class Credentials(BaseModel):
    value: str
    type: str

    class Config:
        orm_mode = True


class User(BaseModel):
    email: str
    username: str
    enabled: bool
    firstName: str
    lastName: str
    attributes: Attributes
    credentials: list[Credentials]

    class Config:
        orm_mode = True

create_user.py

def create_new_keycloak_user(user: User):
    admin = keycloak_service.connect_to_keycloak_as_admin()
    try:
        body = vars(user)
        print(body)
        new_user = admin.create_user(body)
        return new_user
    except Exception as err:
        raise HTTPException(status_code=400, detail=f"User creation failed: {err}")

routing.py

# I also have tried without response_model=User

@router.post("/create-user", response_model=User)
async def create_new_user(user: User):
    create_user.create_new_keycloak_user(user)
    return user

The body I receive in the backend when I try to create user:

{'email': '[email protected]', 'username': 'mverdi', 'enabled': True, 'firstName': 'Jhon', 'lastName': 'Doe', 'attributes': Attributes(locale='ITA', phoneNumber='+391234567891'), 'credentials': [Credentials(value='superpassword01', type='password')]}

I think it's related to this "malformed" JSON, if you notice in the previous JSON I have

'attributes': Attributes(locale='ITA', phoneNumber='+391234567891'),

which is clearly not allowed a thing like this in a properly JSON format. But why I receive as result a thing like that?

Using FastAPI with Python3.10 and Pydantic



Solution 1:[1]

I solved it. The problem was in the file create_user.py

I was converting my user object with vars() who turns my user into a dict (which is not the same thing as a JSON) but instead I needed to use a proper json encoder provided by FastAPI framework.

OLD CODE:

def create_new_keycloak_user(user: User):
    admin = keycloak_service.connect_to_keycloak_as_admin()
    try:
        body = vars(user)
        print(body)
        new_user = admin.create_user(body)
        return new_user
    except Exception as err:
        raise HTTPException(status_code=400, detail=f"User creation failed: {err}")

NEW CODE:

def create_new_keycloak_user(user: User):
    admin = keycloak_service.connect_to_keycloak_as_admin()
    try:
        body = jsonable_encoder(user)
        admin.create_user(body)
    except Exception as err:
        raise HTTPException(status_code=400, detail=f"User creation failed: {err}")

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Melom