Explore o novo chatbot do Developer Center! O MongoDB AI chatbot pode ser acessado na parte superior da sua navegação para responder a todas as suas perguntas sobre o MongoDB .

Saiba por que o MongoDB foi selecionado como um líder no 2024 Gartner_Magic Quadrupnt()

8 Melhores práticas para criar aplicativos FastAPI e MongoDB

Mark Smith8 min read • Published Apr 23, 2024 • Updated Apr 23, 2024
SNIPPET
Facebook Icontwitter iconlinkedin icon
Classifique este artigo
star-empty
star-empty
star-empty
star-empty
star-empty
FastAPI é uma estrutura web moderna e de alto desempenho para construir APIs com Python 3.8 ou posterior, com base em dicas de tipo. Seu design se concentra em codificação rápida e redução de erros, graças à validação automática do modelo de dados e a menos códigos padrão. O suporte do FastAPI para programação assíncrona garante que as APIs sejam eficientes e escaláveis, enquanto os recursos de documentação integrados, como o MongoDB UI e o ReDoc, fornecem ferramentas interativas de pesquisa da API.
FastAPI seamlessly integrates with MongoDB through the Motor library, enabling asynchronous database interactions. This combination supports scalable applications by enhancing both the speed and flexibility of data handling with MongoDB. FastAPI and MongoDB together are ideal for creating applications that manage potentially large amounts of complex and diverse data efficiently. MongoDB is a proud sponsor of the FastAPI project, so you can tell it's a great choice for building applications with MongoDB.
All the techniques described in this article are available on GitHub — check out the source code! With that out of the way, now we can begin…
O FastAPI é particularmente adequado para criar APIs RESTful, em que solicitações de dados e atualizações no banco de dados são feitas usando solicitações HTTP, geralmente com cargas JSON. Mas a estrutura é igualmente excelente como back-end para sites HTML ou até mesmo aplicativos completos de página única (SPAs), onde a maioria das solicitações é feita via JavaScript. (Chamamos isso de pilha FARM — FastAPI, React, MongoDB — mas você pode trocar qualquer estrutura de componente front-end que desejar.) É particularmente flexível em relação ao back-end do banco de dados e à linguagem de modelo usada para renderizar HTML.

Use o driver correto!

There are actually two Python drivers for MongoDB — PyMongo and Motor — but only one of them is suitable for use with FastAPI. Because FastAPI is built on top of ASGI and asyncio, you need to use Motor, which is compatible with asyncio. PyMongo is only for synchronous applications. Fortunately, just like PyMongo, Motor is developed and fully supported by MongoDB, so you can rely on it in production, just like you would with PyMongo.
Você pode instalá-lo executando o seguinte comando em seu terminal (recomendo configurar um ambiente virtual Python primeiro!):
1pip install motor[srv]
The srv extra includes some extra dependencies that are necessary for connecting with MongoDB Atlas connection strings.
Once installed, you'll need to use the AsyncIOMotorClient in the motor.motor_asyncio package.
1from fastapi import FastAPI
2from motor.motor_asyncio import AsyncIOMotorClient
3
4app = FastAPI()
5
6# Load the MongoDB connection string from the environment variable MONGODB_URI
7CONNECTION_STRING = os.environ['MONGODB_URI']
8
9# Create a MongoDB client
10client = AsyncIOMotorClient(CONNECTION_STRING)
Observe que a cadeia de conexão não é armazenada no código! O que me leva a...

Mantenha seus segredos seguros

It's very easy to accidentally commit secret credentials in your code and push them to relatively insecure places like shared Git repositories. I recommend making it a habit to never put any secret in your code.
When working on code, I keep my secrets in a file called .envrc — the contents get loaded into environment variables by a tool called direnv. Other tools for keeping sensitive credentials out of your code include envdir, a library like python-dotenv, and there are various tools like Honcho and Foreman. You should use whichever tool makes the most sense to you. Whether the file that keeps your secrets is called .env or .envrc or something else, you should add that filename to your global gitignore file so that it never gets added to any repository.
In production, you should use a KMS (key management system) such as Vault, or perhaps the cloud-native KMS of whichever cloud you may be using to host your application. Some people even use a KMS to manage their secrets in development.

Inicialize sua conexão de banco de dados corretamente

Embora eu tenha inicializado minha conexão de banco de dados no código acima no nível superior de um pequeno aplicativo FastAPI, é uma prática recomendada inicializar e fechar normalmente a conexão do cliente, respondendo a eventos de inicialização e desligamento em seu aplicativo FastAPI. Você também deve anexar seu cliente ao objeto de aplicativo do FastAPI para disponibilizá-lo às suas funções de operação de caminho, onde quer que elas estejam em sua base de código. (Outras estruturas às vezes se referem a elas como “routes” ou “endpoints.”. A FastAPI as chama de “path operations.”) Se você confiar em uma variável global, precisará se preocupar em importá-la em todos os lugares necessários, o que pode ser confuso.
O trecho de código abaixo mostra como responder ao início e ao desligamento do seu aplicativo e como lidar com o cliente em resposta a cada um desses eventos:
1from contextlib import asynccontextmanager
2from logging import info @asynccontextmanager
3async def db_lifespan(app: FastAPI):
4 # Startup
5 app.mongodb_client = AsyncIOMotorClient(CONNECTION_STRING)
6 app.database = app.mongodb_client.get_default_database()
7 ping_response = await app.database.command("ping")
8 if int(ping_response["ok"]) != 1:
9 raise Exception("Problem connecting to database cluster.")
10 else:
11 info("Connected to database cluster.")
12
13 yield
14
15 # Shutdown
16 app.mongodb_client.close()
17
18
19app: FastAPI = FastAPI(lifespan=db_lifespan)

Considere usar um ODM Pydantial

Um ODM, ou mapeador de documentos de objetos, é uma biblioteca que converte entre documentos e objetos em seu código. É em grande parte análogo a um ORM no mundo dos bancos de dados RDBMS. O uso de um ODM é um tópico complexo e, às vezes, ele pode ocultar coisas importantes, como a forma como os dados são armazenados e atualizados no banco de dados ou até mesmo alguns recursos avançados do MongoDB que você pode querer aproveitar. Seja qual for o ODM que você escolher, você deve examiná-lo altamente para ter certeza de que ele fará o que você deseja e crescerá com você.
If you're choosing an ODM for your FastAPI application, definitely consider using a Pydantic-based ODM, such as ODMantic or Beanie. The reason you should prefer one of these libraries is that FastAPI is built with tight integration to Pydantic. This means that if your path operations return a Pydantic object, the schema will automatically be documented using OpenAPI (which used to be called Swagger), and FastAPI also provides nice API documentation under the path "/docs". As well as documenting your interface, it also provides validation of the data you're returning.
1class Profile(Document):
2 """
3 A profile for a single user as a Beanie Document.
4
5 Contains some useful information about a person.
6 """
7
8 # Use a string for _id, instead of ObjectID:
9 id: Optional[str] = Field(default=None, description="MongoDB document ObjectID")
10 username: str
11 birthdate: datetime
12 website: List[str]
13
14 class Settings:
15 # The name of the collection to store these objects.
16 name = "profiles"
17
18# A sample path operation to get a Profile:
19@app.get("/profiles/{profile_id}")
20async def get_profile(profile_id: str) -> Profile:
21 """
22 Look up a single profile by ID.
23 """
24 # This API endpoint demonstrates using Motor directly to look up a single
25 # profile by ID.
26 profile = await Profile.get(profile_id)
27 if profile is not None:
28 return profile
29 else:
30 raise HTTPException(
31 status_code=404, detail=f"No profile with id '{profile_id}'"
32 )
O objeto de perfil acima é documentado automaticamente no caminho "/docs":
A screenshot of the auto-generated documentation

Você pode usar o Motor diretamente

If you feel that working directly with the Python MongoDB driver, Motor, makes more sense to you, I can tell you that it works very well for many large, complex MongoDB applications in production. If you still want the benefits of automated API documentation, you can document your schema in your code so that it will be picked up by FastAPI.

Lembre-se de que alguns BSON têm mais tipos do que JSON

Como muitos aplicativos FastAPI incluem endpoints que fornecem dados JSON que são recuperados do MongoDB, é importante lembrar que determinados tipos que você pode armazenar em seu banco de dados, especialmente os tipos ObjectID e Binary, não existem no JSON. Felizmente, a FastAPI lida com datas e horários para você, codificando-os como strings formatadas.
Existem algumas maneiras diferentes de lidar com mapeamentos ObjectID. A primeira é evitá-los completamente usando um tipo compatível com JSON (como uma string) para valores de ID. Em muitos casos, isso não é prático, porque você já tem dados ou apenas porque o ObjectID é o tipo mais apropriado para sua chave primária. Nesse caso, você provavelmente desejará converter ObjectIDs em uma representação de string ao converter para JSON e fazer o inverso com dados que estão sendo enviados para seu aplicativo.
If you're using Beanie, it automatically assumes that the type of your _id is an ObjectID, and so will set the field type to PydanticObjectId, which will automatically handle this serialization mapping for you. You won't even need to declare the id in your model!

Defina tipos de Pydantials para suas respostas de operação de caminho

Se você especificar o tipo de resposta de suas operações de caminho, a FastAPI validará as respostas fornecidas e também filtrará todos os campos que não estejam definidos no tipo de resposta.
Because ODMantic and Beanie use Pydantic under the hood, you can return those objects directly. Here's an example using Beanie:
1@app.get("/people/{profile_id}")
2async def read_item(profile_id: str) -> Profile:
3 """ Use Beanie to look up a Profile. """
4 profile = await Profile.get(profile_id)
5 return profile
Se você estiver usando o Motor, ainda poderá obter os benefícios de documentação, conversão, validação e filtragem retornando dados do documento, mas fornecendo o modelo Pydantic ao decorador:
1@app.get(
2 "/people/{profile_id}",
3 response_model=Profile,
4)
5async def read_item(profile_id: str) -> Mapping[str, Any]:
6 # This API endpoint demonstrates using Motor directly to look up a single
7 # profile by ID.
8 #
9 # It uses response_model (above) to tell FastAPI the schema of the data
10 # being returned, but it returns a dict directly, so that conversion and
11 # validation is done by FastAPI, meaning you don't have to copy values
12 # manually into a Profile before returning it.
13 profile = await app.profiles.find_one({"_id": profile_id})
14 if profile is not None:
15 return profile

Lembre-se de modelar seus dados adequadamente

Um erro comum que as pessoas cometem ao construir servidores de API RESTful no MongoDB é armazenar os objetos de sua interface API exatamente da mesma maneira em seu MongoDB database. Isso pode funcionar muito bem em casos simples, especialmente se o aplicativo for uma API CRUD relativamente direta.
In many cases, however, you'll want to think about how to best model your data for efficient updates and retrieval and aid in maintaining referential integrity and reasonably sized indexes. This is a topic all of its own, so definitely check out the series of design pattern articles on the MongoDB website, and maybe consider doing the free Advanced Schema Design Patterns online course at MongoDB University. (There are lots of amazing free courses on many different topics at MongoDB University.)
Se estiver trabalhando com um modelo de dados diferente no banco de dados e no aplicativo, será necessário mapear os valores recuperados do banco de dados e os valores fornecidos por meio de solicitações às operações do caminho da API. Separar o modelo físico do modelo de negócios tem a vantagem de permitir que você altere o esquema do banco de dados sem necessariamente alterar o esquema da API (e vice-versa).
Even if you're not mapping data returned from the database (yet), providing a Pydantic class as the response_model for your path operation will convert, validate, document, and filter the fields of the BSON data you're returning, so it provides lots of value! Here's an example of using this technique in a FastAPI app:
1# A Pydantic class modelling the *response* schema.
2class Profile(BaseModel):
3 """
4 A profile for a single user.
5 """
6 id: Optional[str] = Field(
7 default=None, description="MongoDB document ObjectID", alias="_id"
8 )
9 username: str
10 residence: str
11 current_location: List[float]
12
13# A path operation that returns a Profile object as JSON:
14@app.get(
15 "/profiles/{profile_id}",
16 response_model=Profile, # This tells FastAPI that the returned object must match the Profile schema.
17)
18async def get_profile(profile_id: str) -> Mapping[str, Any]:
19 # Uses response_model (above) to tell FastAPI the schema of the data
20 # being returned, but it returns a dict directly, so that conversion and
21 # validation is done by FastAPI, meaning you don't have to copy values
22 # manually into a Profile before returning it.
23 profile = await app.profiles.find_one({"_id": profile_id})
24 if profile is not None:
25 return profile # Return BSON document (Mapping). Conversion etc will be done automatically.
26 else:
27 raise HTTPException(
28 status_code=404, detail=f"No profile with id '{profile_id}'"
29 )

Use o FastAPI e o MongoDB Generator de pilha completa

My amazing colleagues have built an app generator to do a lot of these things for you and help get you up and running as quickly as possible with a production-quality, dockerized FastAPI, React, and MongoDB service, backed by tests and continuous integration. You can check it out at the Full-Stack FastAPI MongoDB GitHub Repository.
The homepage of an app built with the FastAPI Generator

Conclusão

Hopefully, this article has provided you with the knowledge to build a FastAPI application that will scale in both the amount of code you write, and the data you need to store. We're always looking for more tricks and tips for building applications with FastAPI and MongoDB, so if you have some suggestions, why not open a ticket on GitHub and we can have a chat?

Queremos saber o que você está construindo!

We love to know what you're building with FastAPI or any other framework — whether it's a hobby project or an enterprise application that's going to change the world. Let us know what you're building at the MongoDB Community Forums. It's also a great place to stop by if you're having problems — someone on the forums can probably help you out!
Principais comentários nos fóruns
Forum Commenter Avatar
Alessio_RuggiAlessio Ruggi2 quarters ago

Estou comentando apenas para apontar que o link para o Github parece não funcionar


Forum Commenter Avatar
Anuj_UpadhyayaAnuj Upadhyayalast week

Hello @DeveloperCenter,

I followed these steps and the APIs were working fine until few months ago. Also, I have not used Motor and gone with pymongo[srv]. The mongo db is starting to throw connection timeout error intermittently. Following is my setup code:

def db_lifespan(app: FastAPI):
# Startup
server_api = ServerApi(‘1’)
app.mongodb_client = MongoClient(CONNECTION_STRING,
maxIdleTimeMS=600000,
maxConnecting=5,
timeoutMS=90000,
socketTimeoutMS=90000,
serverMonitoringMode=“poll”,
server_api=server_api)
app.database = app.mongodb_client.get_database(DB_NAME)
ping_response = app.database.command(“ping”)
if int(ping_response[“ok”]) != 1:
raise Exception(“Problem connecting to database cluster.”)
else:
logger.info(“Connected to database cluster.”)

yield

# Shutdown
app.mongodb_client.close() 

Could anyone please help me out with the issue?


Facebook Icontwitter iconlinkedin icon
Classifique este artigo
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Tutorial

Uma leve introdução às listas vinculadas com o MongoDB


Apr 02, 2024 | 13 min read
Artigo

As 4 principais razões pelas quais você deve usar o MongoDB


Sep 23, 2022 | 9 min read
Tutorial

Crie uma Java REST API com Quarkus e Eclipse JNoSQL para MongoDB


Jan 30, 2024 | 6 min read
Tutorial

Proteja sua API com o Spring Data MongoDB e o Microsoft EntraID


Apr 02, 2024 | 8 min read