Visão geral
FastAPI O FastAPI é uma estrutura web Python assíncrona moderna, de alto desempenho e pronta para produção, projetada para criar APIs usando dicas padrão do tipo Python. Neste tutorial, você pode aprender como construir um aplicação CRUD completo que integra MongoDB e FastAPI.
Arquitetura não bloqueante
A arquitetura assíncrona e não bloqueante da FastAPI permite que ela lide com milhares de solicitações simultâneas sem depender de várias threads. Ele usa o loop de eventos asyncio
do Python para gerenciar a simultaneidade por meio de corrotinas. Isso permite que o aplicação suspenda uma solicitação enquanto aguarda o retorno das queries. Isso reduz o uso de memória e pode reduzir a latência.
Recursos e integrações integrados
A FastAPI tem várias integrações e recursos integrados, incluindo os seguintes componentes:
Pydentic para análise, validação e serialização automáticas de dados
OpenAPI e JSON schema para documentação de API interativa e gerada automaticamente
Um sistema leve de injeção de dependência Pythonic para código limpo e testável
Suporte para autenticação e autorização de token web OAuth2 e JSON
Esses recursos minimizam o código boilerplate para simplificar o desenvolvimento. Para obter mais informações sobre os recursos da FastAPI, consulte o site da FastAPI.
Tutorial
Você pode encontrar o aplicativo de amostra concluído para este tutorial no MongoDB com repositório Github do projeto de amostra FastAPI.
Pré-requisitos
Certifique-se de ter os seguintes componentes instalados e configurados antes de iniciar este tutorial:
Python v3.9 - 3.11
Um cluster MongoDB Atlas . Para saber como configurar um cluster, consulte o guiaComeçando do para mais informações.
Configuração
Instale dependências, conecte-se ao MongoDB e inicie seu servidor FastAPI:
Clone o exemplo de código de exemplo
Execute o seguinte comando no seu terminal para clonar o código do repositório mongodb-pymongo-fastapi do Github:
git clone git@github.com:mongodb-developer/mongodb-pymongo-fastapi.git cd mongodb-pymongo-fastapi
Instalar as dependências necessárias
Dica
Ative um ambiente virtual
Instalar suas dependências do Python em um virtualenv permite a você instalar versões de suas bibliotecas para projetos individuais. Antes de executar qualquer comando pip
, certifique-se de que seu virtualenv
esteja ativo.
Execute o seguinte comando no seu terminal para instalar as dependências listadas no arquivo requirements.txt
:
cd mongodb-pymongo-fastapi pip install -r requirements.txt
Pode levar alguns minutos para baixar e instalar suas dependências.
Recupere sua string de conexão
Siga o guia Find Your MongoDB Atlas Connection string para recuperar sua string de conexão.
Execute o seguinte código no seu terminal para criar uma variável de ambiente para armazenar sua string de conexão:
export MONGODB_URL="mongodb+srv://<username>:<password>@<url>/<db>?retryWrites=true&w=majority"
Dica
Redefinir variáveis de ambiente
Sempre que você iniciar uma nova sessão de terminal, deverá redefinir esta variável de ambiente. Você pode usar direnv para facilitar esse processo.
Conecte o aplicativo ao seu cluster
Todo o código do aplicação de exemplo é armazenado no arquivo app.py no repositório mongodb-pymongo-fastapi do Github.
Use este código para executar as seguintes ações:
Conecte-se ao MongoDB Atlas cluster usando o método
AsyncMongoClient()
com a variável de ambienteMONGODB_URL
e especificando o banco de dados chamadocollege
.Crie um ponteiro para o banco de dados
college
.Criar um ponteiro para a coleção
students
client = AsyncMongoClient(os.environ["MONGODB_URL"],server_api=pymongo.server_api.ServerApi(version="1", strict=True,deprecation_errors=True)) db = client.get_database("college") student_collection = db.get_collection("students")
A chamada AsyncMongoClient()
inclui um parâmetro server_api
para habilitar o recurso de API estável em sua conexão. Certifique-se de que seu sistema use servidores MongoDB com versão 5.0 ou posterior. Para obter mais informações, consulte a seção API estável deste guia.
Revise os modelos de banco de dados
Este aplicação tem três modelos, o StudentModel
, o UpdateStudentModel
e o StudentCollection
. Estes modelos são definidos no arquivo app.py
.
Todos os modelos no aplicação se baseiam no Pydantic BaseModel
, que fornece validação básica de tipo, análise e serialização JSON e tratamento básico de erros.
Classe EstudanteModel
StudentModel
é o modelo primário utilizado como modelo de resposta para a maioria dos endpoints.
O MongoDB usa _id
como identificador padrão para documentos. No entanto, no Pyantic, os nomes de campo que começam com um sublinhado são tratados como atributos privados e não podem receber valores diretamente. Para trabalhar ao redor disso, podemos nomear o campo id
no modelo Pydentic, mas dado um alias de _id
para que ele mapeie corretamente para MongoDB.
O campo id
é do tipo PyObjectId
, um tipo personalizado anotado com um BeforeValidator
que força o valor em uma string. Isso garante que o ObjectId
do MongoDB possa ser aceito e serializado corretamente pelo modelo.
Esta configuração requer as seguintes opções do model_config
:
populate_by_name=True
: Permite que o modelo seja inicializado usando o nome do campo (id
) ou seu alias (_id
)arbitrary_types_allowed=True
: habilita o suporte para tipos personalizados, comoPyObjectId
O campo id
também é definido como opcional com um valor padrão de None
, portanto, uma nova instância StudentModel
pode ser criada sem especificar um id
. O MongoDB gera automaticamente um _id
quando o documento é inserido e esse valor é retornado nas respostas da API.
O model_config
também inclui uma configuração do json_schema_extra
que define dados de exemplo utilizados na documentação OpenAPI (Swagger) gerada automaticamente do FastAPI.
Você pode ver a definição StudentModel
no seguinte código no arquivo app.py
:
# Represents an ObjectId field in the database. # It will be represented as a `str` on the model so that it can be serialized to JSON. PyObjectId = Annotated[str, BeforeValidator(str)] class StudentModel(BaseModel): """ Container for a single student record. """ # The primary key for the StudentModel, stored as a `str` on the instance. # This will be aliased to ``_id`` when sent to MongoDB, # but provided as ``id`` in the API requests and responses. id: Optional[PyObjectId] = Field(alias="_id", default=None) name: str = Field(...) email: EmailStr = Field(...) course: str = Field(...) gpa: float = Field(..., le=4.0) model_config = ConfigDict( populate_by_name=True, arbitrary_types_allowed=True, json_schema_extra={ "example": { "name": "Jane Doe", "email": "jdoe@example.com", "course": "Experiments, Science, and Fashion in Nanophotonics", "gpa": 3.0, } }, )
Classe UpdateStudentModel
O UpdateStudentModel
tem as seguintes diferenças principais do StudentModel
:
Não tem um atributo
id
, pois este não pode ser modificadoTodos os campos são opcionais, então você pode fornecer apenas os campos que deseja atualizar
As variáveis
mongo_config
incluemjson_encoders={ObjectId: str}
A FastAPI codifica e decodifica dados como strings JSON, que não suportam todos os tipos de dados que o tipo de dados BSON do MongoDB pode armazenar. O BSON tem suporte para mais tipos de dados não nativos JSON, incluindo ObjectId
que é utilizado para o atributo UUID padrão, _id
. Por conta disso, você deve converter ObjectId
objetos em strings antes de armazená-los no campo _id
. A configuração json_encoders
instrui o Pydatic a fazer isso.
Para obter mais informações sobre como o BSON se compara ao JSON, consulte o artigo JSON e BSON do MongoDB.
Você pode ver a definição UpdateStudentModel
no seguinte código no arquivo app.py
:
class UpdateStudentModel(BaseModel): """ A set of optional updates to be made to a document in the database. """ name: Optional[str] = None email: Optional[EmailStr] = None course: Optional[str] = None gpa: Optional[float] = None model_config = ConfigDict( arbitrary_types_allowed=True, json_encoders={ObjectId: str}, json_schema_extra={ "example": { "name": "Jane Doe", "email": "jdoe@example.com", "course": "Experiments, Science, and Fashion in anophotonics", "gpa": 3.0, } }, )
Classe EstudanteCollection
A classe StudentCollection
é definida para encapsular uma lista de instâncias do StudentModel
. O objetivo desse endpoint é fornecer proteção contra o JSON sequestro, em que um usuário mal-intencionado tenta acessar dados confidenciais explorando como os navegadores lidam com arrays JSON. Para obter mais informações, leia o artigo JSON sequestro no site do Haacked.
Você pode ver a definição StudentCollection
no seguinte código no arquivo app.py
:
class StudentCollection(BaseModel): """ A container holding a list of `StudentModel` instances """ students: List[StudentModel]
Revise as rotas de aplicativos
A tabela a seguir descreve as rotas do aplicação definidas neste aplicação:
route | em ação |
---|---|
| Criar um novo aluno |
| Ver uma lista de todos os alunos |
| Ver um único aluno |
| Atualizar um aluno |
| Excluir um aluno |
Estas rotas são definidas no arquivo app.py
, conforme descrito nas seguintes seções:
Rotas dos alunos
A rota create_student
recebe os dados do novo aluno como uma string JSON em uma solicitação POST
. Ele decodifica o corpo da solicitação JSON em um dicionário Python e, em seguida, o passa para o cliente MongoDB .
A resposta do método insert_one
inclui o _id
do aluno recém-criado, fornecido como id
porque esse endpoint especifica response_model_by_alias=False
na chamada do remodelador post
. Após inserir o novo aluno, o método utiliza o inserted_id
para localizar o documento correto e devolvê-lo no JSONResponse
.
A FastAPI retorna um código de status HTTP 200
por padrão, mas essa rota retorna um 201
("Criado") para indicar explicitamente que o aluno foi criado.
Você pode ver a definição create_student
no seguinte código no arquivo app.py
:
async def create_student(student: StudentModel = Body(...)): """ Insert a new student record. A unique ``id`` will be created and provided in the response. """ new_student = student.model_dump(by_alias=True, exclude=["id"]) result = await student_collection.insert_one(new_student) new_student["_id"] = result.inserted_id return new_student
Ler rotas
O aplicação tem uma rota para visualizar todos os alunos e outra para visualizar um aluno específico, especificado por seu id
.
Você pode ver a definição list_students
no seguinte código no arquivo app.py
:
async def list_students(): """ List all the student data in the database. The response is unpaginated and limited to 1000 results. """ return StudentCollection(students=await student_collection.find().to_list(1000))
Observação
Paginação de resultados
Este exemplo utiliza o método to_list()
; mas em um aplicação real, recomendamos usar os parâmetros skip e limite em find
para paginar seus resultados.
A rota detalhada do aluno tem um parâmetro de caminho de id
, que o FastAPI passa como um argumento para a função show_student
. Ele utiliza o id
para tentar encontrar o aluno correspondente no banco de dados.
Se um documento com o id
especificado não existir, ele emitirá um HTTPException
com status de 404
.
Você pode ver a definição show_students
no seguinte código no arquivo app.py
:
async def show_student(id: str): """ Get the record for a specific student, looked up by ``id``. """ if ( student := await student_collection.find_one({"_id": ObjectId(id)}) ) is not None: return student raise HTTPException(status_code=404, detail="Student {id} not found")
Atualizar rota
A rota update_student
funciona de forma semelhante a uma combinação das rotas create_student
e show_student
. Ele recebe o id
do aluno para atualizar e os novos dados no corpo JSON.
Esta rota itera todos os parâmetros nos dados recebidos e modifica apenas os parâmetros fornecidos. Ele usa o método find_one_and_update() para $set.
Se não houver campos para atualizar, ele retornará o documento StudentModel
original. Se não conseguir encontrar um documento correspondente para atualizar ou retornar, será gerado um erro 404
.
Você pode ver a definição update_student
no seguinte código no arquivo app.py
:
async def update_student(id: str, student: UpdateStudentModel = Body(...)): """ Update individual fields of an existing student record. Only the provided fields will be updated. Any missing or `null` fields will be ignored. """ student = { k: v for k, v in student.model_dump(by_alias=True).items() if v is not None } if len(student) >= 1: update_result = await student_collection.find_one_and_update( {"_id": ObjectId(id)}, {"$set": student}, return_document=ReturnDocument.AFTER, ) if update_result is not None: return update_result else: raise HTTPException(status_code=404, detail=f"Student {id} not found") # The update is empty, so return the matching document: if (existing_student := await student_collection.find_one({"_id": ObjectId(id)})) is not None: return existing_student raise HTTPException(status_code=404, detail=f"Student {id} not found")
Excluir rota
O delete_student
atua em um único documento, então você deve fornecer um id
na URL. Se ele encontrar um documento correspondente e excluí-lo com êxito, ele retornará um status HTTP de 204
("Sem conteúdo") e não retornará um documento. Se não for possível encontrar um aluno com o id
especificado, será gerado um erro 404
.
Você pode ver a definição delete_student
no seguinte código no arquivo app.py
:
async def delete_student(id: str): """ Remove a single student record from the database. """ delete_result = await student_collection.delete_one({"_id": ObjectId(id)}) if delete_result.deleted_count == 1: return Response(status_code=status.HTTP_204_NO_CONTENT) raise HTTPException(status_code=404, detail=f"Student {id} not found")
Teste a API
Agora que você entende como o aplicação funciona, pode começar a usar seus endpoints. Use as etapas a seguir para enviar solicitações para seus endpoints e ver os resultados:
Enviar solicitações
Navegue até http://127.0.0.1:8000/Docs. A imagem seguinte mostra a interface gerada pelo servidor FastAPI.

Clique no endpoint para o qual deseja enviar uma solicitação, preencha todos os parâmetros necessários e clique em Execute. No endpoint Show Student , você pode ver os dados de amostra definidos na variável StudentModel.model_config
.
Dica
Use o curl para testar sua API
Se preferir usar a linha de comando, você pode enviar uma solicitação usando o comando curl
, como este:
curl -X POST "http://127.0.0.1:8000/students/" \ -H "Content-Type: application/json" \ -d '{"name": "Jane Doe", "email": "jdoe@example.com", "course": "Physics", "gpa": 3.8}'
Próximos passos
Agora que você tem uma compreensão básica de como a FastAPI se integra ao MongoDB e ao driver PyMongo Async, você pode adicionar mais recursos. A lista a seguir inclui algumas sugestões de como você pode adicionar a este aplicação:
Melhores práticas
As seções a seguir descrevem algumas melhores práticas para integrar o FastAPI ao MongoDB e ao driver PyMongo Async.
Segurança e ambiente
Armazenar credenciais confidenciais diretamente no código do aplicação pode causar exposição acidental nos sistemas de controle de versão. Em vez disso, use variáveis de ambiente para armazenar connection strings, chaves de API e outras informações confidenciais.
Para ambientes de desenvolvimento, você pode usar as seguintes FERRAMENTAS para gerenciar variáveis de ambiente:
direnv: Carrega automaticamente variáveis de ambiente de um arquivo
.envrc
ao inserir um diretóriopython-dotenv: Carrega variáveis de ambiente de um arquivo
.env
dentro do seu aplicação Pythonenvdir: define variáveis de ambiente a partir de arquivos em um diretório
Honcho: Carrega variáveis de ambiente de arquivos de configuração
Independentemente da ferramenta de controle de variável de ambiente que você escolher, adicione quaisquer arquivos que contenham segredos (como .env
, .envrc
ou semelhantes) ao arquivo .gitignore
para evitar que eles sejam comprometidos com o controle de versão.
Para sistemas de produção, use um Sistema de Gerenciamento de Chaves (KMS). Você também pode usar soluções KMS em seu ambiente de desenvolvimento para aumentar a segurança.
Ciclo de vida da conexão do banco de dados
Gerencie adequadamente o ciclo de vida da conexão do MongoDB inicializando e fechando as conexões do cliente em resposta aos eventos de inicialização e desligamento do aplicação FastAPI. Essa abordagem é mais robusta do que inicializar conexões no nível do módulo.
Anexe seu cliente MongoDB ao objeto de aplicação FastAPI para torná-lo acessível a todas as funções de operação de caminho em toda a sua base de código. Isso elimina a necessidade de variáveis globais e simplifica o gerenciamento de dependência.
Use os eventos de duração do FastAPI para lidar com o gerenciamento de conexões:
import os from contextlib import asynccontextmanager from logging import info from fastapi import FastAPI from pymongo import AsyncMongoClient async def db_lifespan(app: FastAPI): # Startup app.mongodb_client = AsyncMongoClient(os.environ["MONGODB_URL"]) app.database = app.mongodb_client.get_default_database() ping_response = await app.database.command("ping") if int(ping_response["ok"]) != 1: raise Exception("Problem connecting to database cluster.") else: info("Connected to database cluster.") yield # Shutdown await app.mongodb_client.close() app: FastAPI = FastAPI(lifespan=db_lifespan)
Manipulação de tipos de BSON vs JSON
Os endpoints FastAPI que fornecem dados JSON ao MongoDB podem conter tipos ObjectId
e Binary
, que não são nativamente suportados em JSON.
Você pode serializar o ObjectId
de várias maneiras:
Usar IDs baseados em string: substitua
ObjectId
por valores de string compatíveis com JSON para campos_id
. Essa abordagem pode funcionar bem para novos aplicativos, mas pode não ser adequada se você tiver dados existentes.Conversão automática: converta valores
ObjectId
em representações de string ao serializar para JSON e analise strings de volta paraObjectId
ao processar dados de entrada.Integração com o Pydentic: use as anotações de tipo do Pydantial para lidar com a conversão automática, conforme demonstrado no tipo
PyObjectId
deste tutorial.Mapeadores de documentos de objetos (ODMs): use um ODM como Beanie, que pressupõe que os campos
_id
usemObjectId
por padrão e lida automaticamente com a serialização e a desserialização.
Modelagem de dados
Separe seu esquema de banco de dados do esquema de API para manter a flexibilidade. Isso permite que você modifique as estruturas de documento do MongoDB sem alterar a interface da API.
Forneça uma classe Pydantial como response_model
para que sua operação de caminho converta, valide, documento e filtre os campos dos dados BSON retornados. O seguinte exemplo de código mostra como implementar esta técnica:
# A Pydantic class modelling the *response* schema. class Profile(BaseModel): """ A profile for a single user. """ id: Optional[str] = Field( default=None, description="MongoDB document ObjectID", alias="_id" ) username: str residence: str current_location: List[float] # A path operation that returns a Profile object as JSON. app = FastAPI() async def get_profile(profile_id: str) -> Mapping[str, Any]: # Uses response_model to automatically convert, validate, and document # the returned dict without manual Profile object creation. profile = await app.profiles.find_one({"_id": profile_id}) if profile is not None: # Return BSON document. FastAPI converts it automatically. return profile else: raise HTTPException( status_code=404, detail=f"No profile with id '{profile_id}'" )
Mais recursos
Para obter mais informações sobre a integração do FastAPI, consulte os seguintes recursos:
- Gerador de aplicativos Full Stack FastAPI do MongoDB
Apresentando a publicação do blog sobre a pilha FARMA (FastAPI, React e MongoDB)
Para obter suporte ou contribuir para a MongoDB Community, consulte a Comunidade de desenvolvedores MongoDB.