Python + Flask REST API, how to convert data keys between camelcase and snakecase?
Asked Answered
L

1

9

I am learning Python, and coding simple REST API using Flask micro-framework.

I am using SQLAlchemy for Object-relational-mapping and Marshmallow for Object-serialization/deserialization.

I am using snakecase for my variable names(according to PEP8).

I need to convert JSON object keys from camelcase to snakecase when receiving data from front-end(Angular) and vice versa, when returning response data.

What is the best approach to do this using Flask ?

I was unable to find a good answer on the internet.

Lassiter answered 9/6, 2019 at 13:50 Comment(1)
Do you have problems with the Flask API or the conversion implementation? Can you also give some examples of correct conversions?Wake
M
8

You don't convert your keys, because you don't need to. Data is not code, the keys in JSON are not variables. They are not subject to PEP8 and you don't convert them.

If you have a convention for your JSON object keys, stick to it everywhere, in your front end and back end. Then use the Marshmallow 3.x data_key argument for a field to set the key name in the JSON document when loading and dumping.

E.g.

class UserSchema(Schema):
    first_name = fields.String(data_key="firstName")
    last_name = fields.Email(data_key='lastName')

If you want to automate this for all your fields, you could provide your own Schema.on_bind_field() implementation to generate a data_key value from the field name:

import re
from functools import partial

from marshmallow import Schema

_snake_case = re.compile(r"(?<=\w)_(\w)")
_to_camel_case = partial(_snake_case.sub, lambda m: m[1].upper())

class CamelCasedSchema(Schema):
    """Gives fields a camelCased data key"""
    def on_bind_field(self, field_name, field_obj, _cc=_to_camel_case):
        field_obj.data_key = _cc(field_name.lower())

Demo:

>>> from marshmallow import fields
>>> class UserSchema(CamelCasedSchema):
...     first_name = fields.String()
...     last_name = fields.String()
...
>>> schema = UserSchema()
>>> schema.load({"firstName": "Eric", "lastName": "Idle"})
{'first_name': 'Eric', 'last_name': 'Idle'}
>>> schema.dump({"first_name": "John", "last_name": "Cleese"})
{'firstName': 'John', 'lastName': 'Cleese'}

The examples section of the Marshmallow documentation has a similar recipe.

If you are using Marshmallow 2.x, then there are two arguments to set: load_from and dump_to.

Mcrae answered 9/6, 2019 at 14:1 Comment(2)
There is now a recipe in the docs for automatically camel-casing keys: marshmallow.readthedocs.io/en/latest/…Lobster
No I'm sorry I disagree. You work with the convention of your internal traffic as a whole. You don't defer to pythonic snake case just because one of your systems insists on it for data management in. Especially nowadays with Microservice architecture; one might have numerous servers using numerous languages. And don't forget: some of those servers might be hybrid (SSR like Next/Nuxt/etc. and be a combination. Others might be fullstack and serving a mixture of outputs). So who takes precedence? If I have an existing API framework I will continue that framework in spite of python.Lorikeet

© 2022 - 2024 — McMap. All rights reserved.