2

Suppose I have a simple SQLAlchemy class and a simple Flask o FastAPI implementation like this:

from sqlalchemy.ext.declarative import declarative_base
from pydantic import BaseModel
Base = declarative_base()

class A(Base):
    __tablename__ = 'as'
    my_id = Column(String)

class AModel(BaseModel):
    myId:str = None

And a simple endpoint like this:

@app_router.get('/a')
def get_all_a(session:Session = Depends(get_session)):
    return session.query(A).all()

How could I ensure that the returned list of this endpoint yields in camelCase like this:

[{'myId': 'id1'},{'myId': 'id2'}, ...]

Note: My application is rather complex, as I also have pagination implemented and some post-processings require a little bit more that just snake_case to camelCase conversion, so the simplest solution would be the best.

I've tried overriding dict() methods and similar stuff with no luck, simply cannot understand how FastAPI processes the results to obtain a JSON.

Manu Sisko
  • 269
  • 2
  • 17
  • This Stack OV Question could help you [Convert data keys between camelcase & snakecase](https://stackoverflow.com/questions/56515134/python-flask-rest-api-how-to-convert-data-keys-between-camelcase-and-snakecas), also a reference to marshmallow official docs could be useful as well [marshmallow - docs](https://marshmallow.readthedocs.io/en/latest/examples.html#inflection-camel-casing-keys) – Franco Gil Nov 19 '21 at 15:06

1 Answers1

4

2023 may update:

This solution is compatible with pydantic < v2.0 and will not necessarily reflect future release of this amazing library

require a little bit more that just snake_case to camelCase conversion

Well, if you don't use response_model you don't have a lot of choices.

The solution is returning your dict with a conversion from snake_case to camelCase. You have functions that do it recursively.

Why it is the best solution ?

using regex it's super fast, faster than any lib that convert dict to obj like pydantic

If you definitely don't want to do this, well your only solution is using pydantic models, attrs or dataclasses and convert your db query output to one of those models type with camelCase variable name (dirty).

Since you are using fastapi you should use all the power of it.

I would suggest this:

from typing import List

from sqlalchemy.ext.declarative import declarative_base
from pydantic import BaseModel, Field
from pydantic import parse_obj_as
Base = declarative_base()

class A(Base):
    __tablename__ = 'as'
    my_id = Column(String)

class AModel(BaseModel):
    myId: str = Field(alias="my_id", default=None)

@app_router.get('/a', response_model=List[AModel])
def get_all_a(session:Session = Depends(get_session)):
    return parse_obj_as(List[AModel], session.query(A).all())

Keep in mind that having classes variables in CamelCase is not a good practice.

The gold answer would be to not return camel but snake and let your client do the work of conversion if needed.

Bastien B
  • 1,018
  • 8
  • 25
  • At this point I think that edge for the solution could be this [pydantic Docs - Alias Generator](https://pydantic-docs.helpmanual.io/usage/model_config/#alias-generator) – Franco Gil Nov 24 '21 at 19:06
  • @Franco the problem with alias_generator is that you can't initialize fields with their snake syntax, and we need it here because de db output is snake. To use it we will need to convert from snake to camel and so having 2 time the inital problem to resolve. – Bastien B Nov 24 '21 at 20:47
  • At the end I solve this topic using a column "synonym" `sqlalchemy.orm import synonym`, but I am sill thinking that there is another door in this maze ja. – Franco Gil Nov 24 '21 at 22:10