Ir para o conteúdo

Usando Dataclasses

FastAPI é construído em cima do Pydantic, e eu tenho mostrado como usar modelos Pydantic para declarar requisições e respostas.

Mas o FastAPI também suporta o uso de dataclasses da mesma forma:

from dataclasses import dataclass
from typing import Union

from fastapi import FastAPI


@dataclass
class Item:
    name: str
    price: float
    description: Union[str, None] = None
    tax: Union[float, None] = None


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item

Isso ainda é suportado graças ao Pydantic, pois ele tem suporte interno para dataclasses.

Então, mesmo com o código acima que não usa Pydantic explicitamente, o FastAPI está usando Pydantic para converter essas dataclasses padrão para a versão do Pydantic.

E claro, ele suporta o mesmo:

  • validação de dados
  • serialização de dados
  • documentação de dados, etc.

Isso funciona da mesma forma que com os modelos Pydantic. E na verdade é alcançado da mesma maneira por baixo dos panos, usando Pydantic.

Informação

Lembre-se de que dataclasses não podem fazer tudo o que os modelos Pydantic podem fazer.

Então, você ainda pode precisar usar modelos Pydantic.

Mas se você tem um monte de dataclasses por aí, este é um truque legal para usá-las para alimentar uma API web usando FastAPI. 🤓

Dataclasses em response_model

Você também pode usar dataclasses no parâmetro response_model:

from dataclasses import dataclass, field
from typing import List, Union

from fastapi import FastAPI


@dataclass
class Item:
    name: str
    price: float
    tags: List[str] = field(default_factory=list)
    description: Union[str, None] = None
    tax: Union[float, None] = None


app = FastAPI()


@app.get("/items/next", response_model=Item)
async def read_next_item():
    return {
        "name": "Island In The Moon",
        "price": 12.99,
        "description": "A place to be playin' and havin' fun",
        "tags": ["breater"],
    }

A dataclass será automaticamente convertida para uma dataclass Pydantic.

Dessa forma, seu esquema aparecerá na interface de documentação da API:

Dataclasses em Estruturas de Dados Aninhadas

Você também pode combinar dataclasses com outras anotações de tipo para criar estruturas de dados aninhadas.

Em alguns casos, você ainda pode ter que usar a versão do Pydantic das dataclasses. Por exemplo, se você tiver erros com a documentação da API gerada automaticamente.

Nesse caso, você pode simplesmente trocar as dataclasses padrão por pydantic.dataclasses, que é um substituto direto:

from dataclasses import field  # (1)
from typing import List, Union

from fastapi import FastAPI
from pydantic.dataclasses import dataclass  # (2)


@dataclass
class Item:
    name: str
    description: Union[str, None] = None


@dataclass
class Author:
    name: str
    items: List[Item] = field(default_factory=list)  # (3)


app = FastAPI()


@app.post("/authors/{author_id}/items/", response_model=Author)  # (4)
async def create_author_items(author_id: str, items: List[Item]):  # (5)
    return {"name": author_id, "items": items}  # (6)


@app.get("/authors/", response_model=List[Author])  # (7)
def get_authors():  # (8)
    return [  # (9)
        {
            "name": "Breaters",
            "items": [
                {
                    "name": "Island In The Moon",
                    "description": "A place to be playin' and havin' fun",
                },
                {"name": "Holy Buddies"},
            ],
        },
        {
            "name": "System of an Up",
            "items": [
                {
                    "name": "Salt",
                    "description": "The kombucha mushroom people's favorite",
                },
                {"name": "Pad Thai"},
                {
                    "name": "Lonely Night",
                    "description": "The mostests lonliest nightiest of allest",
                },
            ],
        },
    ]
  1. Ainda importamos field das dataclasses padrão.

  2. pydantic.dataclasses é um substituto direto para dataclasses.

  3. A dataclass Author inclui uma lista de dataclasses Item.

  4. A dataclass Author é usada como o parâmetro response_model.

  5. Você pode usar outras anotações de tipo padrão com dataclasses como o corpo da requisição.

    Neste caso, é uma lista de dataclasses Item.

  6. Aqui estamos retornando um dicionário que contém items, que é uma lista de dataclasses.

    O FastAPI ainda é capaz de serializar os dados para JSON.

  7. Aqui o response_model está usando uma anotação de tipo de uma lista de dataclasses Author.

    Novamente, você pode combinar dataclasses com anotações de tipo padrão.

  8. Note que esta função de operação de rota usa def regular em vez de async def.

    Como sempre, no FastAPI você pode combinar def e async def conforme necessário.

    Se você precisar de uma atualização sobre quando usar qual, confira a seção "Com pressa?" na documentação sobre async e await.

  9. Esta função de operação de rota não está retornando dataclasses (embora pudesse), mas uma lista de dicionários com dados internos.

    O FastAPI usará o parâmetro response_model (que inclui dataclasses) para converter a resposta.

Você pode combinar dataclasses com outras anotações de tipo em muitas combinações diferentes para formar estruturas de dados complexas.

Confira as dicas de anotação no código acima para ver mais detalhes específicos.

Saiba Mais

Você também pode combinar dataclasses com outros modelos Pydantic, herdar deles, incluí-los em seus próprios modelos, etc.

Para saber mais, confira a documentação do Pydantic sobre dataclasses.

Versão

Isso está disponível desde a versão 0.67.0 do FastAPI. 🔖