String-Valued Enums

Source module: fastapi_utils.enums


Using enums as fields of a JSON payloads is a great way to force provided values into one of a limited number of self-documenting fields.

However, integer-valued enums can make it more difficult to inspect payloads and debug endpoint calls, especially if the client and server are using different code bases.

For most applications, the development benefits of using string-valued enums vastly outweigh the minimal performance/bandwidth tradeoffs.

Creating a string-valued enum for use with pydantic/FastAPI that is properly encoded in the OpenAPI spec is as easy as inheriting from str in addition to enum.Enum:

from enum import Enum

class MyEnum(str, Enum):
    value_a = "value_a"
    value_b = "value_b"

One nuisance with this approach is that if you rename one of the enum values (for example, using an IDE), you can end up with the name and value differing, which may lead to confusing errors.

For example, if you refactored the above as follows (forgetting to çhange the associated values), you’ll get pydantic parsing errors if you use the new names instead of the values in JSON bodies:

from enum import Enum

class MyEnum(str, Enum):
    choice_a = "value_a"  # pydantic would only parse "value_a" to MyEnum.choice_a
    choice_b = "value_b"

The standard library’s enum package provides a way to automatically generate values: auto.

By default, auto will generate integer values, but this behavior can be overridden and the official python docs include a detailed section about how to do this.

Rather than repeating this definition in each new project, to reduce boilerplate you can just inherit from fastapi_utils.enums.StrEnum directly to get this behavior:

from enum import auto

from fastapi_utils.enums import StrEnum


class MyEnum(StrEnum):
    choice_a = auto()
    choice_b = auto()


assert MyEnum.choice_a.name == MyEnum.choice_a.value == "choice_a"
assert MyEnum.choice_b.name == MyEnum.choice_b.value == "choice_b"

You can also use fastapi_utils.enums.CamelStrEnum to get camelCase values:

from enum import auto

from fastapi_utils.enums import CamelStrEnum


class MyEnum(CamelStrEnum):
    choice_one = auto()
    choice_two = auto()


assert MyEnum.choice_a.name == MyEnum.choice_a.value == "choiceOne"
assert MyEnum.choice_b.name == MyEnum.choice_b.value == "choiceTwo"