Pular para o conteúdo

    Capítulo 5, Básico

    Parâmetros de consulta

    O que vem depois do `?` na URL: filtros, busca, ordenação, paginação. Ajustam **como** você quer ver os dados, e não **quais** dados são o recurso.

    Parâmetros obrigatórios e opcionais

    Qualquer parâmetro da função que não faz parte do caminho vira um parâmetro de consulta. Sem valor padrão, ele é obrigatório. Com valor padrão, é opcional:

    basico/cap05_parametros_consulta.pylinhas 10 a 23
    from fastapi import FastAPI
    from fastapi.testclient import TestClient
    
    app = FastAPI()
    
    
    @app.get("/busca")
    def buscar(q: str, limite: int = 10, ordem: str | None = None):
        return {"q": q, "limite": limite, "ordem": ordem}
    
    
    cliente = TestClient(app)
    print(cliente.get("/busca?q=caneta").json())
    print(cliente.get("/busca?q=caneta&limite=50&ordem=preco").json())
    
    Saída
    {'q': 'caneta', 'limite': 10, 'ordem': None}
    {'q': 'caneta', 'limite': 50, 'ordem': 'preco'}
    

    O limite assumiu o padrão 10 quando não veio. A ordem ficou None (JSON null). Já o q não tem padrão, e esquecê-lo é um erro:

    basico/cap05_parametros_consulta.pylinhas 25 a 27
    resposta = cliente.get("/busca")
    erro = resposta.json()["detail"][0]
    print(resposta.status_code, erro["loc"], erro["type"])
    
    Saída
    422 ['query', 'q'] missing
    

    Opcional: `str | None = None`, e não `str = None`

    Muito material escreve nome: str = None. Funciona, mas mente sobre o tipo: a função diz que recebe um str e dá None como padrão. O verificador de tipos reclama, e o documento OpenAPI perde a informação de que o valor pode ser nulo:

    basico/cap05_parametros_consulta.pylinhas 32 a 44
    @app.get("/a")
    def com_none_simples(nome: str = None):
        return nome
    
    
    @app.get("/b")
    def com_uniao(nome: str | None = None):
        return nome
    
    
    caminhos = app.openapi()["paths"]
    print(caminhos["/a"]["get"]["parameters"][0]["schema"])
    print(caminhos["/b"]["get"]["parameters"][0]["schema"])
    
    Saída
    {'type': 'string', 'title': 'Nome'}
    {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'title': 'Nome'}
    

    A segunda forma descreve a verdade (string ou null), e é a que eu uso sempre.

    Booleanos e listas

    Um bool aceita true, false, 1, 0, yes, no, on e off. Para receber vários valores do mesmo parâmetro, declare uma lista com Query:

    basico/cap05_parametros_consulta.pylinhas 49 a 60
    from typing import Annotated
    
    from fastapi import Query
    
    
    @app.get("/produtos")
    def produtos(ativo: bool = True, etiquetas: Annotated[list[str] | None, Query()] = None):
        return {"ativo": ativo, "etiquetas": etiquetas}
    
    
    print(cliente.get("/produtos?ativo=no").json())
    print(cliente.get("/produtos?etiquetas=novo&etiquetas=oferta").json())
    
    Saída
    {'ativo': False, 'etiquetas': None}
    {'ativo': True, 'etiquetas': ['novo', 'oferta']}
    

    Validação com `Query`

    O Query impõe tamanho mínimo e máximo em textos e limites em números, e as regras vão para a documentação:

    basico/cap05_parametros_consulta.pylinhas 65 a 76
    @app.get("/pesquisa")
    def pesquisa(
        termo: Annotated[str, Query(min_length=3, max_length=20)],
        pagina: Annotated[int, Query(ge=1)] = 1,
        por_pagina: Annotated[int, Query(ge=1, le=100)] = 20,
    ):
        return {"termo": termo, "pagina": pagina, "por_pagina": por_pagina}
    
    
    print(cliente.get("/pesquisa?termo=caneta").json())
    resposta = cliente.get("/pesquisa?termo=ab&por_pagina=500")
    print(resposta.status_code, [e["loc"][-1] for e in resposta.json()["detail"]])
    
    Saída
    {'termo': 'caneta', 'pagina': 1, 'por_pagina': 20}
    422 ['termo', 'por_pagina']
    

    Os dois erros voltaram juntos: o termo curto demais e o por_pagina acima de 100. O FastAPI valida tudo e informa tudo de uma vez, em vez de parar no primeiro problema.

    ParâmetroVai emObrigatório?
    /usuarios/{id}CaminhoSempre
    ?q=abc sem padrãoConsultaSim
    ?q=abc com padrão ou NoneConsultaNão
    Objeto PydanticCorpo (próximo capítulo)Conforme o modelo

    Exercício 1

    Uma busca com limites

    Crie GET /livros com os parâmetros autor (opcional), ano_minimo (inteiro, padrão 1900, mínimo 1000) e limite (inteiro, padrão 10, entre 1 e 50). Confira os padrões e um valor inválido.