Enum Path Parameters

Difficulty: Beginner

Sometimes you want a path or query parameter to accept only a fixed set of values. Python's Enum class combined with FastAPI provides an elegant solution. When you use an Enum type for a parameter, FastAPI automatically validates that the provided value is one of the allowed options and documents the valid choices in the Swagger UI.

To create an Enum for use with FastAPI, you typically inherit from both str and Enum (creating a StrEnum). This ensures the enum values are strings that can be used directly in URL paths and JSON responses. For example, class ModelName(str, Enum) defines a string enum whose values work seamlessly with FastAPI's routing.

When you declare a parameter with an Enum type, FastAPI restricts the allowed values to only the enum members. If a client sends a value that is not in the enum, FastAPI returns a 422 validation error listing the valid options. This validation is automatic - you do not need any manual checking code.

In the Swagger UI, Enum parameters appear as dropdown menus showing all valid options. This makes the API self-documenting and easy to test. Clients can see exactly which values are acceptable without reading external documentation.

You can also use IntEnum for integer path parameters with restricted values. This works the same way but with integer values instead of strings. For example, class Priority(int, Enum) with values like LOW = 1, MEDIUM = 2, HIGH = 3.

Enum parameters can be used as both path parameters and query parameters. For query parameters, the enum provides a constrained choice list. For path parameters, each enum value becomes a valid URL segment. In both cases, the value is converted to the corresponding Python Enum member in your handler function.

In your handler function, you receive the Enum member, not just the raw string. You can access .value to get the string value, or compare directly with enum members using == or is. Python's pattern matching (match/case) also works well with enum parameters.

Code examples

String Enum for Path Parameters

from enum import Enum
from fastapi import FastAPI

class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"

app = FastAPI()

@app.get("/models/{model_name}")
def get_model(model_name: ModelName):
    if model_name is ModelName.alexnet:
        return {"model": model_name.value, "message": "Deep Learning FTW!"}
    if model_name is ModelName.lenet:
        return {"model": model_name.value, "message": "Classic CNN"}
    return {"model": model_name.value, "message": "Residual learning"}

# GET /models/alexnet -> {"model": "alexnet", "message": "Deep Learning FTW!"}
# GET /models/resnet  -> {"model": "resnet", "message": "Residual learning"}
# GET /models/invalid -> 422 Error with valid options listed

The ModelName enum restricts the path parameter to three valid values. In Swagger UI, this shows as a dropdown. The handler receives a ModelName enum member, which can be compared with 'is' or accessed via .value.

Enum for Query Parameters

from enum import Enum
from fastapi import FastAPI

class SortOrder(str, Enum):
    asc = "asc"
    desc = "desc"

class Category(str, Enum):
    electronics = "electronics"
    clothing = "clothing"
    books = "books"
    food = "food"

app = FastAPI()

@app.get("/products")
def list_products(
    category: Category | None = None,
    sort: SortOrder = SortOrder.desc,
):
    return {
        "category": category.value if category else None,
        "sort": sort.value,
    }

# GET /products                    -> category=null, sort="desc"
# GET /products?category=books     -> category="books", sort="desc"
# GET /products?sort=asc           -> category=null, sort="asc"
# GET /products?category=invalid   -> 422 Error

Enums work for query parameters too. Optional enum parameters use Category | None = None. The enum ensures only valid values are accepted, and Swagger UI shows a dropdown for selection.

Integer Enum and Multiple Enums

from enum import Enum, IntEnum
from fastapi import FastAPI

class Priority(IntEnum):
    low = 1
    medium = 2
    high = 3
    critical = 4

class Status(str, Enum):
    open = "open"
    in_progress = "in_progress"
    closed = "closed"

app = FastAPI()

@app.get("/tickets")
def list_tickets(
    status: Status | None = None,
    min_priority: Priority = Priority.low,
):
    return {
        "status_filter": status.value if status else None,
        "min_priority": min_priority.value,
    }

@app.post("/tickets")
def create_ticket(
    priority: Priority = Priority.medium,
):
    return {"priority": priority.value, "priority_name": priority.name}

# GET /tickets?status=open&min_priority=3
# -> {"status_filter": "open", "min_priority": 3}

IntEnum works with integer values. Multiple enums can be combined in a single endpoint. The .name property gives the enum member name (like 'high'), while .value gives the value (like 3).

Key points

Concepts covered

Enum, str Enum, IntEnum, Restricted Values, Documentation