Pranithan T.
Pranithan T.

Reputation: 383

FastAPI: How to map arbitrary-attribute dict to pydantic model to let swagger display detail

I have a FastAPI project that one of its endpoint looks like this:

@app.post(
    response=SomePydanticModel() # how to compose SomePydanticModel here???
)
def my_end_point():
    response = {
        "ZOOQ-700Z71": [
            {"product_id": "prod_001", "product_name": "Product 001", "quantity": 10},
            {"product_id": "prod_002", "product_name": "Product 002", "quantity": 20},
            {"product_id": "prod_004", "product_name": "Product 004", "quantity": 30},
        ],
        "0071-ZOGKNQ": [
            {"product_id": "prod_001", "product_name": "Product 001", "quantity": 10},
            {"product_id": "prod_003", "product_name": "Product 003", "quantity": 7},
            {"product_id": "prod_008", "product_name": "Product 008", "quantity": 2},
        ],
        "0071-Z0GKQ7": [
            {"product_id": "prod_002", "product_name": "Product 002", "quantity": 12},
            {"product_id": "prod_007", "product_name": "Product 007", "quantity": 6},
        ],
        "ZZOQ-ZXOCT9": [
            {"product_id": "prod_004", "product_name": "Product 004", "quantity": 100},
        ],
        "2007-ZCKOZR": [
            {"product_id": "prod_004", "product_name": "Product 004", "quantity": 30},
            {"product_id": "prod_005", "product_name": "Product 005", "quantity": 20},
        ],
    }

As you can see that my response is arbitrary-attribute dict, its attributes formatted xxxx-xxxxxx are Purchase Order ID. How can I write SomePydanticModel to represent my response? Therefore, I want the swagger to show the description of my response.

Upvotes: 5

Views: 6027

Answers (1)

alex_noname
alex_noname

Reputation: 32233

You could use a model with Dict as root type with keys as constrained string constr with regex pattern.

For example:

from typing import Dict, List

from fastapi import FastAPI
from pydantic import BaseModel, constr

app = FastAPI()


class Product(BaseModel):
    product_id: str
    product_name: str
    quantity: int


ConStrType = constr(regex=r'^[A-Z0-9]{4}-[A-Z0-9]{6}$')
ProductDict = Dict[ConStrType, List[Product]]


class ProductModel(BaseModel):
    __root__: ProductDict



@app.post("/products", response_model=ProductModel)
def my_end_point():
    return {
        "ZOOQ-700Z71": [
            {"product_id": "prod_001", "product_name": "Product 001", "quantity": 10},
            {"product_id": "prod_002", "product_name": "Product 002", "quantity": 20},
            {"product_id": "prod_004", "product_name": "Product 004", "quantity": 30},
        ],
        "0071-ZOGKNQ": [
            {"product_id": "prod_001", "product_name": "Product 001", "quantity": 10},
            {"product_id": "prod_003", "product_name": "Product 003", "quantity": 7},
            {"product_id": "prod_008", "product_name": "Product 008", "quantity": 2},
        ],
        "0071-Z0GKQ7": [
            {"product_id": "prod_002", "product_name": "Product 002", "quantity": 12},
            {"product_id": "prod_007", "product_name": "Product 007", "quantity": 6},
        ],
        "ZZOQ-ZXOCT9": [
            {"product_id": "prod_004", "product_name": "Product 004", "quantity": 100},
        ],
        "2007-ZCKOZR": [
            {"product_id": "prod_004", "product_name": "Product 004", "quantity": 30},
            {"product_id": "prod_005", "product_name": "Product 005", "quantity": 20},
        ],
    }

Upvotes: 3

Related Questions