O Modelo de Ciclo de Vida de Requisição do FastAPI
O FastAPI é frequentemente descrito recurso por recurso: suporte a async, documentação automática, injeção de dependência, validação Pydantic.
Esses recursos são reais, mas não são add-ons separados aparafusados em um framework web comum.
Eles são um ciclo de vida: uma requisição entra como um evento ASGI, é combinada com uma operação de caminho cujo grafo de dependências já foi resolvido na inicialização, tem suas entradas validadas antes que o corpo da sua função seja executado, e tem suas saídas revalidadas e filtradas antes de saírem.
Entender bem o FastAPI significa entender esse ciclo de vida como um único pipeline, não como uma lista de verificação de capacidades independentes.
Esta página constrói esse modelo mental; Fundamentos do FastAPI e Injeção de Dependência cobrem a sintaxe prática que este modelo explica por baixo.
Resumo
- Uma requisição FastAPI passa por um único ciclo de vida - despacho ASGI, resolução de dependência, validação Pydantic, execução do handler, serialização da resposta - e o comportamento de cada estágio só faz sentido à luz dos outros.
- Por que Importa: A maioria dos comportamentos confusos do FastAPI (por que uma função síncrona não bloqueou, por que erros de validação nunca chegam ao seu código, por que uma dependência rodou duas vezes) remonta a um estágio desse ciclo de vida que foi mal compreendido, não a um bug.
- Conceitos Chave: ASGI, o grafo de dependências, validação Pydantic, a divisão síncrona/assíncrona em threadpool, filtragem de response_model.
- Quando Usar Este Modelo: Para raciocinar sobre onde a validação acontece, decidir se um handler deve ser
async def, depurar por que o teardown de uma dependência rodou em um momento inesperado, ou explicar por que o FastAPI precisa de Starlette e Pydantic por baixo dele. - Limitações / Trade-offs: A flexibilidade do ciclo de vida vem da introspecção em tempo de execução e da resolução de dependências por requisição, ambos adicionam sobrecarga mensurável em comparação a um framework sem nenhuma camada de validação ou DI.
- Tópicos Relacionados: Roteamento e middleware do Starlette, modelo de requisição síncrona do WSGI, motor de validação do Pydantic, Uvicorn e servidores ASGI em geral.
Fundamentos
FastAPI não é um servidor, e nem mesmo é um framework completo no sentido em que Django é.
É uma camada tipada de requisição/resposta construída sobre Starlette, um toolkit ASGI que já fornece roteamento, middleware e o cliente de teste, além de Pydantic, que fornece o motor de validação e serialização de dados.
ASGI (Asynchronous Server Gateway Interface) é a peça que torna isso possível: ao contrário do contrato síncrono de uma requisição por chamada do WSGI, uma aplicação ASGI é um único callable assíncrono que recebe scope, um awaitable receive e um awaitable send, e pode manter uma conexão aberta, aguardar I/O sem bloquear outras requisições, e lidar com WebSockets usando a mesma interface.
Uma forma útil de visualizar a relação: Starlette é o motor que executa o protocolo ASGI e encontra a função certa para chamar; FastAPI é o que acontece quando você também impõe que as entradas e saídas da função sejam tipadas e validadas.
Essa estrutura importa porque uma grande parte do que as pessoas chamam de "recursos do FastAPI" - tipagem de parâmetros de caminho/query, corpos de requisição, filtragem de resposta - são na verdade recursos do Pydantic que o FastAPI conecta ao roteamento do Starlette nos pontos certos do ciclo de vida.
Mecânicas e Interações
O ciclo de vida na verdade tem duas fases: uma que roda uma vez na inicialização, e outra que roda em cada requisição.
Na inicialização, o FastAPI inspeciona a assinatura de cada função de operação de caminho - seus parâmetros, suas dicas de tipo e quaisquer padrões Depends(...) - e constrói um grafo de dependências para essa rota, incluindo sub-dependências de dependências, tudo resolvido antecipadamente para que o trabalho por requisição seja apenas percorrer uma árvore conhecida.
Requisição em
-> Servidor ASGI (Uvicorn) entrega o scope para a aplicação
-> Roteador Starlette combina caminho + método
-> FastAPI percorre o grafo de dependências pré-construído (de cima para baixo, sub-deps primeiro)
-> Pydantic valida parâmetros de caminho/query/corpo contra os modelos da rota
-> função de operação de caminho executa (async no loop, sync em um threadpool)
-> valor de retorno validado/filtrado contra response_model
-> resposta enviada; dependências do tipo `yield` executam o teardown depoisCada requisição então percorre esse grafo: dependências resolvem de cima para baixo, um determinado callable de dependência é invocado apenas uma vez por requisição, mesmo que várias outras dependências dependam dele, e qualquer dependência definida com yield tem seu código pós-yield adiado até depois que a resposta foi gerada.
A divisão síncrona/assíncrona é uma mecânica central, não uma escolha de estilo: uma operação de caminho ou dependência async def roda diretamente no event loop, enquanto uma def comum é despachada automaticamente para um threadpool externo para que não possa bloquear outras requisições concorrentes - é por isso que "apenas não use async" não faz, por si só, um endpoint escalar pior, embora limite a concorrência ao tamanho do threadpool.
A validação acontece antes que o corpo da sua função seja executado, não dentro dele: o FastAPI analisa o corpo ASGI bruto, o combina com o modelo Pydantic do parâmetro ou tipo escalar, e levanta um 422 com erros em nível de campo automaticamente se falhar, então um handler só vê dados já válidos e já tipados.
from fastapi import Depends, FastAPI
app = FastAPI()
def get_settings():
return {"env": "prod"}
def get_client(settings: dict = Depends(get_settings)):
return {"base_url": settings["env"]}
@app.get("/status")
def status(client: dict = Depends(get_client)):
return client # get_settings e get_client rodaram uma vez cada, não duasConsiderações Avançadas e Aplicações
Como o grafo de dependências e os modelos Pydantic são resolvidos através dos mecanismos de introspecção do Python, o FastAPI paga um custo real por requisição que um framework sem camada de validação não paga: este é o trade-off para obter esquemas OpenAPI automáticos, autocompletar no editor e segurança de fronteira gratuitamente.
O threadpool que suporta operações de caminho síncronas tem um tamanho finito (o Starlette o define como um worker pool limitado), então uma aplicação que é majoritariamente de funções síncronas fazendo I/O bloqueante eventualmente enfileirará atrás desse pool sob carga, o que é um teto de escalabilidade fácil de perder até que o tráfego aumente - veja Rotas Assíncronas e Bancos de Dados para a alternativa de drivers assíncronos.
response_model não é apenas metadados para a documentação: o FastAPI realmente revalida e filtra o objeto que sua função retorna contra ele, que é o mecanismo que impede que um campo como um hash de senha vaze de uma resposta JSON, mesmo que o objeto retornado ainda tenha esse atributo, mas também significa que um valor de retorno incompatível falha no estágio de resposta, não no estágio de requisição.
Tarefas em segundo plano (BackgroundTasks) rodam após a resposta ter sido enviada ao cliente, mas ainda dentro do mesmo ciclo de vida do worker/requisição, o que as torna adequadas para logging ou notificações "fire-and-forget", mas não para qualquer coisa que o cliente precise saber que foi bem-sucedida - veja Tarefas em Segundo Plano e Workers para onde esse limite se situa.
| Abordagem | Força | Fraqueza | Melhor Ajuste |
|---|---|---|---|
| Ciclo de vida ASGI + DI + Pydantic do FastAPI | Validação automática, docs e DI tipada com async nativo | Sobrecarga de introspecção e validação por requisição; dependências síncronas limitadas pelo tamanho do threadpool | APIs onde segurança de entrada, geração de esquema e I/O assíncrono são importantes |
| Starlette Puro (sem camada FastAPI) | Sobrecarga mínima, controle total do ASGI | Sem validação automática, DI ou OpenAPI - tudo feito manualmente | Serviços críticos de latência que não precisam de contratos de requisição tipados |
| Framework WSGI (ex: Flask) | Modelo mental mais simples, ecossistema síncrono maduro | Sem concorrência async nativa; I/O bloqueante prende um worker | Aplicações primariamente síncronas sem demandas de I/O concorrente elevadas |
Equívocos Comuns
- "Marcar uma rota como
async defa torna automaticamente mais rápida." Isso só ajuda quando o handler realmente aguarda I/O; umasync deflimitado pela CPU ainda bloqueia o event loop inteiro para todas as outras requisições concorrentes, o que umdefsíncrono rodando no threadpool não faria. - "Depends é apenas uma forma de chamar uma função auxiliar." Uma dependência é resolvida uma vez por requisição, cacheada para essa requisição se reutilizada em outro lugar no mesmo grafo, e pode ser substituída completamente em testes via
app.dependency_overrides- nada disso é oferecido por uma simples chamada de função. - "A validação acontece dentro da minha função de endpoint." Ela acontece antes que sua função seja invocada; quando seu código roda, os dados já passaram pelas verificações do Pydantic, que é por isso que levantar seu próprio 422 manualmente raramente é necessário.
- "response_model é apenas para a documentação OpenAPI." Ele ativamente filtra e revalida o valor que sua função retorna contra ele, que é o mecanismo que impede que um campo como um hash de senha vaze de uma resposta JSON, mesmo que o objeto retornado ainda tenha esse atributo.
- "FastAPI é um servidor web do zero." Ele não tem servidor próprio; Uvicorn (ou outro servidor ASGI) é o que realmente aceita conexões, e FastAPI é a aplicação tipada que o servidor chama.
FAQs
O que "ASGI" realmente significa para como o FastAPI lida com uma requisição?
Significa que a aplicação é um único callable assíncrono recebendo scope, receive e send, o que permite ao FastAPI manter uma conexão aberta e aguardar I/O (chamadas de banco de dados, chamadas HTTP, mensagens WebSocket) sem bloquear outras requisições concorrentes no mesmo event loop.
O FastAPI é seu próprio servidor web?
Não. Uvicorn ou outro servidor ASGI aceita as conexões TCP reais e chama o objeto da aplicação FastAPI; o trabalho do FastAPI começa assim que uma requisição já chegou a ele como um evento ASGI.
Quando o grafo de dependências de uma rota é construído - por requisição, ou uma vez?
Uma vez, na inicialização, quando o FastAPI inspeciona a assinatura de cada operação de caminho e seus padrões Depends(...). Por requisição, ele apenas percorre esse grafo já conhecido em vez de redescobri-lo.
Uma dependência usada por duas outras dependências roda duas vezes em uma requisição?
Não. O FastAPI resolve e cacheia cada callable de dependência uma vez por requisição por padrão, então sub-dependências compartilhadas (como uma sessão de banco de dados) são computadas uma única vez, mesmo que várias outras dependências precisem delas.
Toda operação de caminho deve ser `async def`?
Apenas se a função realmente aguardar I/O. Um async def limitado pela CPU bloqueia todo o event loop pela duração desse trabalho; um def síncrono fazendo o mesmo trabalho de CPU roda em um threadpool, o que não bloqueia o trabalho assíncrono de outras requisições.
O que acontece se os dados da requisição falharem na validação Pydantic?
O FastAPI retorna automaticamente uma resposta 422 com detalhes de erro em nível de campo, antes que o corpo da sua função de operação de caminho seja executado - seu código nunca vê entrada inválida.
O que `response_model` realmente faz em tempo de execução?
Ele valida e filtra o valor que sua função retorna contra esse modelo, removendo quaisquer campos que não estejam declarados nele, que é por isso que ele é usado para impedir que campos internos vazem para uma resposta JSON.
Quando os blocos de teardown de dependência baseados em `yield` realmente rodam?
Depois que a resposta já foi gerada (e, dependendo da versão e configuração, potencialmente após ter sido enviada), o que os torna adequados para fechar uma sessão ou conexão de banco de dados, mas inadequados para qualquer coisa que precise afetar o corpo da resposta em si.
Por que uma operação de caminho síncrona poderia ser um risco de escalabilidade?
Porque ela roda em um threadpool limitado; uma vez que requisições síncronas concorrentes excedem o tamanho do pool, as adicionais enfileiram atrás dele, criando latência que o código limitado por I/O assíncrono compartilhando o event loop não incorreria.
Posso substituir uma dependência para testes?
Sim - app.dependency_overrides[some_dependency] = fake_dependency a substitui para toda a aplicação ou sessão de teste sem alterar o código da rota, o que só funciona porque as dependências são resolvidas através deste grafo em vez de serem chamadas diretamente.
As tarefas em segundo plano atrasam a resposta para o cliente?
Não, elas rodam após a resposta ter sido enviada, que é exatamente por isso que são apropriadas para logging ou notificações, mas não para qualquer coisa que o chamador precise confirmar antes que a requisição seja concluída.
Por que o FastAPI precisa de Starlette e Pydantic?
Starlette fornece o roteamento ASGI, middleware e mecânicas de despacho; Pydantic fornece o motor de validação e serialização de dados. A contribuição do FastAPI é conectar modelos de requisição/resposta tipados aos pontos de despacho do Starlette e gerar OpenAPI a partir deles.
Relacionados
- Fundamentos do FastAPI - rotas práticas, parâmetros e documentação automática
- Injeção de Dependência -
Depends, sub-dependências e substituições de teste na prática - Modelos de Requisição e Resposta - modelos Pydantic na fronteira de requisição/resposta
- Rotas Assíncronas e Bancos de Dados - o lado I/O assíncrono da divisão síncrona/assíncrona
- Middleware e Tratamento de Erros - onde o middleware se encaixa em relação a este ciclo de vida
- Tarefas em Segundo Plano e Workers - o que roda após a resposta ser enviada
Versões do Stack: Esta página foi escrita para FastAPI 0.115+ em Python 3.14 (manutenção: 3.13), usando Pydantic 2 para validação.