You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

7.4 KiB

Corpo - Modelos aninhados

Com o FastAPI, você pode definir, validar, documentar e usar modelos profundamente aninhados de forma arbitrária (graças ao Pydantic).

Campos do tipo Lista

Você pode definir um atributo como um subtipo. Por exemplo, uma list do Python:

{!../../../docs_src/body_nested_models/tutorial001.py!}

Isso fará com que tags seja uma lista de itens mesmo sem declarar o tipo dos elementos desta lista.

Campos do tipo Lista com um parâmetro de tipo

Mas o Python tem uma maneira específica de declarar listas com tipos internos ou "parâmetros de tipo":

Importe List do typing

Primeiramente, importe List do módulo typing que já vem por padrão no Python:

{!../../../docs_src/body_nested_models/tutorial002.py!}

Declare a List com um parâmetro de tipo

Para declarar tipos que têm parâmetros de tipo(tipos internos), como list, dict, tuple:

  • Importe os do modulo typing
  • Passe o(s) tipo(s) interno(s) como "parâmetros de tipo" usando colchetes: [ e ]
from typing import List

my_list: List[str]

Essa é a sintaxe padrão do Python para declarações de tipo.

Use a mesma sintaxe padrão para atributos de modelo com tipos internos.

Portanto, em nosso exemplo, podemos fazer com que tags sejam especificamente uma "lista de strings":

{!../../../docs_src/body_nested_models/tutorial002.py!}

Tipo "set"

Mas então, quando nós pensamos mais, percebemos que as tags não devem se repetir, elas provavelmente devem ser strings únicas.

E que o Python tem um tipo de dados especial para conjuntos de itens únicos, o set.

Então podemos importar Set e declarar tags como um set de strs:

{!../../../docs_src/body_nested_models/tutorial003.py!}

Com isso, mesmo que você receba uma requisição contendo dados duplicados, ela será convertida em um conjunto de itens exclusivos.

E sempre que você enviar esses dados como resposta, mesmo se a fonte tiver duplicatas, eles serão gerados como um conjunto de itens exclusivos.

E também teremos anotações/documentação em conformidade.

Modelos aninhados

Cada atributo de um modelo Pydantic tem um tipo.

Mas esse tipo pode ser outro modelo Pydantic.

Portanto, você pode declarar "objects" JSON profundamente aninhados com nomes, tipos e validações de atributos específicos.

Tudo isso, aninhado arbitrariamente.

Defina um sub-modelo

Por exemplo, nós podemos definir um modelo Image:

{!../../../docs_src/body_nested_models/tutorial004.py!}

Use o sub-modelo como um tipo

E então podemos usa-lo como o tipo de um atributo:

{!../../../docs_src/body_nested_models/tutorial004.py!}

Isso significa que o FastAPI vai esperar um corpo similar à:

{
    "name": "Foo",
    "description": "The pretender",
    "price": 42.0,
    "tax": 3.2,
    "tags": ["rock", "metal", "bar"],
    "image": {
        "url": "http://example.com/baz.jpg",
        "name": "The Foo live"
    }
}

Novamente, apenas fazendo essa declaração, com o FastAPI, você ganha:

  • Suporte do editor de texto (compleção, etc), inclusive para modelos aninhados
  • Conversão de dados
  • Validação de dados
  • Documentação automatica

Tipos especiais e validação

Além dos tipos singulares normais como str, int, float, etc. Você também pode usar tipos singulares mais complexos que herdam de str.

Para ver todas as opções possíveis, cheque a documentação para ostipos exoticos do Pydantic. Você verá alguns exemplos no próximo capitulo.

Por exemplo, no modelo Image nós temos um campo url, nós podemos declara-lo como um HttpUrl do Pydantic invés de como uma str:

{!../../../docs_src/body_nested_models/tutorial005.py!}

A string será verificada para se tornar uma URL válida e documentada no esquema JSON/1OpenAPI como tal.

Atributos como listas de submodelos

Você também pode usar modelos Pydantic como subtipos de list, set, etc:

{!../../../docs_src/body_nested_models/tutorial006.py!}

Isso vai esperar(converter, validar, documentar, etc) um corpo JSON tal qual:

{
    "name": "Foo",
    "description": "The pretender",
    "price": 42.0,
    "tax": 3.2,
    "tags": [
        "rock",
        "metal",
        "bar"
    ],
    "images": [
        {
            "url": "http://example.com/baz.jpg",
            "name": "The Foo live"
        },
        {
            "url": "http://example.com/dave.jpg",
            "name": "The Baz"
        }
    ]
}

/// info | "informação"

Note como o campo images agora tem uma lista de objetos de image.

///

Modelos profundamente aninhados

Você pode definir modelos profundamente aninhados de forma arbitrária:

{!../../../docs_src/body_nested_models/tutorial007.py!}

/// info | "informação"

Note como Offer tem uma lista de Items, que por sua vez possui opcionalmente uma lista Images

///

Corpos de listas puras

Se o valor de primeiro nível do corpo JSON que você espera for um array do JSON (uma lista do Python), você pode declarar o tipo no parâmetro da função, da mesma forma que nos modelos do Pydantic:

images: List[Image]

como em:

{!../../../docs_src/body_nested_models/tutorial008.py!}

Suporte de editor em todo canto

E você obtém suporte do editor em todos os lugares.

Mesmo para itens dentro de listas:

Você não conseguiria este tipo de suporte de editor se estivesse trabalhando diretamente com dict em vez de modelos Pydantic.

Mas você também não precisa se preocupar com eles, os dicts de entrada são convertidos automaticamente e sua saída é convertida automaticamente para JSON também.

Corpos de dicts arbitrários

Você também pode declarar um corpo como um dict com chaves de algum tipo e valores de outro tipo.

Sem ter que saber de antemão quais são os nomes de campos/atributos válidos (como seria o caso dos modelos Pydantic).

Isso seria útil se você deseja receber chaves que ainda não conhece.


Outro caso útil é quando você deseja ter chaves de outro tipo, por exemplo, int.

É isso que vamos ver aqui.

Neste caso, você aceitaria qualquer dict, desde que tenha chaves int com valores float:

{!../../../docs_src/body_nested_models/tutorial009.py!}

/// tip | "Dica"

Leve em condideração que o JSON só suporta str como chaves.

Mas o Pydantic tem conversão automática de dados.

Isso significa que, embora os clientes da API só possam enviar strings como chaves, desde que essas strings contenham inteiros puros, o Pydantic irá convertê-los e validá-los.

E o dict que você recebe como weights terá, na verdade, chaves int e valores float.

///

Recapitulação

Com FastAPI você tem a flexibilidade máxima fornecida pelos modelos Pydantic, enquanto seu código é mantido simples, curto e elegante.

Mas com todos os benefícios:

  • Suporte do editor (compleção em todo canto!)
  • Conversão de dados (leia-se parsing/serialização)
  • Validação de dados
  • Documentação dos esquemas
  • Documentação automática