Overview
FastAPI es un framework web asíncrono de Python moderno, de alto rendimiento y listo para producción, diseñado para crear APIs utilizando anotaciones de tipos estándar de Python. En este tutorial, puedes aprender a compilar una aplicación CRUD completa que integre MongoDB y FastAPI.
Arquitectura no bloqueante
La arquitectura asincrónica y no bloqueante de FastAPI le permite gestionar miles de solicitudes simultáneas sin depender de la multiproceso. Utiliza la de Python
asyncio bucle de eventos para gestionar la concurrencia a través de co-rutinas. Esto permite que la aplicación suspenda una solicitud mientras espera el retorno de las consultas. Esto reduce el uso de memoria y puede reducir la latencia.
Funcionalidades e integraciones integradas
FastAPI cuenta con varias integraciones y funcionalidades incorporadas, incluyendo los siguientes componentes:
Pydantic para el análisis automático de datos, validación y serialización
OpenAPI y JSON Schema para documentación de API autogenerada e interactiva
Un sistema de inyección de dependencias ligero y "phytonico" para un código limpio y comprobable
Soporte para OAuth2 y autenticación y autorización JWT
Estas funcionalidades minimizan el código repetitivo para simplificar el desarrollo. Para obtener más información sobre las capacidades de FastAPI, consulta el Sitio web de FastAPI.
Tutorial
Puedes encontrar la aplicación de muestra completa para este tutorial en el Proyecto de muestra de MongoDB con FastAPI repositorio de GitHub.
Requisitos previos
Asegúrate de tener instalados y configurados los siguientes componentes antes de comenzar este tutorial:
Python v3.9 - 3.11
Un clúster de MongoDB Atlas. Para aprender a configurar un clúster, consulte la Guía para comenzar para más información.
Configuración
Instala las dependencias, conéctate a MongoDB y arranca tu servidor FastAPI:
Clona el ejemplo de código
Ejecuta el siguiente comando en tu terminal para clonar el código del repositorio Github mongodb-pymongo-fastapi:
git clone git@github.com:mongodb-developer/mongodb-pymongo-fastapi.git cd mongodb-pymongo-fastapi
Instala las dependencias necesarias
Tip
Activar un entorno virtual
Instalar tus dependencias de Python en un virtualenv te permite instalar versiones de tus librerías para proyectos individuales. Antes de ejecutar cualquier comando pip, asegúrese de que su virtualenv esté activo.
Ejecuta el siguiente comando en tu terminal para instalar las dependencias listadas en el archivo requirements.txt:
cd mongodb-pymongo-fastapi pip install -r requirements.txt
Puede tardar unos momentos en descargar e instalar sus dependencias.
Recupera tu cadena de conexión
Sigue la Guía para encontrar tu cadena de conexión de MongoDB Atlas para recuperar tu cadena de conexión.
Ejecuta el siguiente código en tu terminal para crear una variable de entorno y almacenar tu cadena de conexión:
export MONGODB_URL="mongodb+srv://<username>:<password>@<url>/<db>?retryWrites=true&w=majority"
Tip
Reiniciar variables de entorno
Cada vez que inicies una nueva sesión de terminal, debes restablecer esta variable de entorno. Puedes usar direnv para facilitar este proceso.
Conecta la aplicación a tu clúster
Todo el código de la aplicación de ejemplo se almacena en el archivo app.py en el mongodb-pymongo-fastapi repositorio de GitHub.
Usa este código para realizar las siguientes acciones:
Conecte a su clúster de MongoDB Atlas usando el método
AsyncMongoClient()con la variable de entornoMONGODB_URLy especificando la base de datos llamadacollege.Cree un puntero a la base de datos
college.Cree un puntero a la colección
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")
La llamada AsyncMongoClient() incluye un parámetro server_api para habilitar la funcionalidad Stable API en tu conexión. Asegúrate de que tu implementación use servidores MongoDB con la versión 5.0 o posterior. Para más información, consulta la sección Stable API de esta guía.
Revisar los Modelos de base de datos
Esta aplicación tiene tres modelos, el StudentModel, el UpdateStudentModel y el StudentCollection. Estos modelos se definen en el archivo app.py.
Todos los modelos de la aplicación se basan en el Pydantic BaseModel, que proporciona validación básica de tipos, análisis y serialización JSON y manejo básico de errores.
Clase StudentModel
StudentModel es el modelo principal utilizado como el modelo de respuesta para la mayoría de los endpoints.
MongoDB utiliza _id como el identificador por defecto para los documentos. Sin embargo, en Pydantic, los nombres de campos que comienzan con un guion bajo se tratan como atributos privados y no se les puede asignar valores directamente. Para solucionar esto, podemos nombrar el campo id en el modelo Pydantic, pero dado un alias de _id para que se mapee correctamente a MongoDB.
El campo id es del tipo PyObjectId, un tipo personalizado anotado con un BeforeValidator que transforma el valor en una string. Esto asegura que el ObjectId de MongoDB pueda ser aceptado y serializado correctamente por el modelo.
Esta configuración requiere las siguientes model_config opciones:
populate_by_name=TruePermite inicializar el modelo usando el nombre del campo (id) o su alias (_id)arbitrary_types_allowed=TrueHabilita el soporte para tipos personalizados, comoPyObjectId
El campo id también se define como opcional con un valor predeterminado de None, por lo que se puede crear una nueva instancia StudentModel sin especificar un id. MongoDB genera automáticamente un _id cuando se inserta el documento, y este valor se devuelve en las respuestas de la API.
El model_config también incluye una configuración de json_schema_extra que define los datos de ejemplo utilizados en la documentación OpenAPI (Swagger) autogenerada de FastAPI.
Puedes ver la definición de StudentModel en el siguiente código en el archivo 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, } }, )
Clase UpdateStudentModel
El UpdateStudentModel tiene las siguientes diferencias clave con respecto al StudentModel:
No tiene un atributo
id, ya que este no puede modificarse.Todos los campos son opcionales, por lo que puedes proporcionar solo los campos que deseas actualizar
Las variables
mongo_configincluyenjson_encoders={ObjectId: str}
FastAPI codifica y decodifica datos como cadenas JSON, que no admiten todos los tipos de datos que el tipo de datos BSON de MongoDB puede almacenar. BSON tiene soporte para más tipos de datos no nativos de JSON, incluyendo ObjectId, que se utiliza para el atributo UUID por defecto, _id. Por este motivo, debes convertir los objetos ObjectId en cadenas antes de almacenarlos en el campo _id. La configuración json_encoders indica a Pydantic que haga esto.
Para obtener más información sobre la comparación entre BSON y JSON, consulta el JSON y BSON artículo de MongoDB.
Puedes ver la definición de UpdateStudentModel en el siguiente código en el archivo 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, } }, )
Clase StudentCollection
La clase StudentCollection está definida para encapsular una lista de instancias de StudentModel. El propósito de este endpoint es proporcionar cierta protección contra el secuestro de JSON, donde un usuario malintencionado intenta acceder a datos sensibles explotando la manera en que los navegadores gestionan los arreglos JSON. Para más información, puedes leer el Secuestro de JSON artículo en el sitio web de Haacked.
Puedes ver la definición de StudentCollection en el siguiente código en el archivo app.py:
class StudentCollection(BaseModel): """ A container holding a list of `StudentModel` instances """ students: List[StudentModel]
Revisar las rutas de la aplicación
La siguiente tabla describe las rutas de aplicación definidas en esta aplicación:
Ruta | Acción |
|---|---|
| Crear un nuevo estudiante |
| Ver una lista de todos los estudiantes |
| Ver un solo estudiante |
| Actualizar un estudiante |
| Borrar a un estudiante |
Estas rutas están definidas en el archivo app.py como se describe en las siguientes secciones:
Rutas para estudiantes
La ruta create_student recibe los nuevos datos del estudiante como una string JSON en una solicitud POST. Decodifica el cuerpo de la solicitud JSON en un diccionario de Python y luego lo pasa a su cliente de MongoDB.
La respuesta del método insert_one incluye el _id del estudiante recién creado, proporcionado como id porque este endpoint especifica response_model_by_alias=False en la llamada del decorador post. Después de insertar el nuevo estudiante, el método utiliza el inserted_id para encontrar el documento correcto y devolver esto en el JSONResponse.
FastAPI devuelve un código de estado HTTP 200 por defecto, pero esta ruta devuelve un 201 ("Creado") para indicar explícitamente que el estudiante fue creado.
Puedes ver la definición de create_student en el siguiente código en el archivo 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
Leer rutas
La aplicación tiene una ruta para visualizar a todos los estudiantes y otra para visualizar a un estudiante individual, especificada por su id.
Puedes ver la definición de list_students en el siguiente código en el archivo 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))
Nota
Paginación de resultados
Este ejemplo utiliza el método to_list(); pero en una aplicación real, recomendamos utilizar los parámetros de omisión y límite en find para paginar tus resultados.
La ruta de detalles del estudiante tiene un parámetro de ruta de id, que FastAPI pasa como argumento a la función show_student. Utiliza el id para intentar encontrar al estudiante correspondiente en la base de datos.
Si no existe un documento con el id especificado, entonces se genera un HTTPException con un estado de 404.
Puedes ver la definición de show_students en el siguiente código en el archivo 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")
Actualizar ruta
La ruta update_student funciona de manera similar a una combinación de las rutas create_student y show_student. Recibe el id del estudiante para actualizar y los nuevos datos en el cuerpo del JSON.
Esta ruta itera sobre todos los parámetros en los datos recibidos y solo modifica los parámetros proporcionados. Utiliza el método find_one_and_update() para $set.
Si no hay campos que actualizar, entonces se devuelve el documento original StudentModel. Si no puede encontrar un documento coincidente para actualizar o devolver, entonces genera un error 404.
Puedes ver la definición de update_student en el siguiente código en el archivo 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")
Borrar ruta
El delete_student actúa sobre un solo documento, por lo que debes proporcionar un id en la URL. Si se encuentra un documento coincidente y se borra correctamente, entonces se devuelve un estado HTTP de 204 ("Sin contenido") y no se devolverá ningún documento. Si no puede encontrar un estudiante con el id especificado, devuelve un error 404.
Puedes ver la definición de delete_student en el siguiente código en el archivo 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")
Probar la API
Ahora que entiendes cómo funciona la aplicación, puedes empezar a usar tus puntos finales. Sigue los siguientes pasos para enviar solicitudes a tus endpoints y ver los resultados:
Enviar solicitudes
Navegue hacia http://127.0.0.1:8000/docs. La imagen que sigue muestra la interfaz generada por el servidor FastAPI.

Haz clic en el endpoint al que deseas enviar una solicitud, rellena los parámetros necesarios y haz clic ExecuteEn el endpoint Show Student, puedes ver los datos de muestra definidos en la variable StudentModel.model_config.
Tip
Usa curl para probar tu API
Si prefieres utilizar la línea de comandos, puedes enviar una solicitud usando el 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 pasos
Ahora que tienes una comprensión básica de cómo FastAPI se integra con MongoDB y el driver asíncrono de PyMongo, puedes añadir más funcionalidades. La siguiente lista incluye algunas sugerencias sobre cómo podrías aportar a esta aplicación:
Mejores prácticas
Las siguientes secciones describen algunas de las mejores prácticas para integrar FastAPI con MongoDB y el driver PyMongo asíncrono.
Seguridad y entorno
Almacenar credenciales sensibles directamente en el código de la aplicación podría provocar una exposición accidental en los sistemas de control de versiones. En su lugar, use variables de entorno para almacenar cadenas de conexión, claves API y otra información confidencial.
Para entornos de desarrollo, puedes usar las siguientes herramientas para gestionar las variables de entorno:
direnv: Carga automáticamente variables de entorno desde un archivo
.envrcal ingresar a un directoriopython-dotenv: Carga las variables de entorno desde un archivo
.envdentro de tu aplicación Python.envdir: Establece variables de entorno a partir de archivos en un directorio
Honcho: Carga variables de entorno desde archivos de configuración
Independientemente de la herramienta de control de variables de entorno que elijas, añade cualquier archivo que contenga secretos (como .env, .envrc o similares) a tu archivo .gitignore para evitar que se incluyan en el control de versiones.
Para implementaciones en producción, utiliza un sistema de gestión de claves (KMS). También puede utilizar soluciones KMS en su entorno de desarrollo para mejorar la seguridad.
Ciclo de Vida de la Conexión de la Base de Datos
Gestiona adecuadamente el ciclo de vida de tu conexión a MongoDB iniciando y cerrando las conexiones del cliente en respuesta a los eventos de inicio y apagado de la aplicación FastAPI. Este enfoque es más robusto que iniciar conexiones a nivel de módulo.
Conecta tu cliente MongoDB al objeto de aplicación de FastAPI para hacerlo accesible a todas las funciones de operaciones de ruta en toda tu base de código. Esto elimina la necesidad de variables globales y simplifica la gestión de dependencias.
Usa los eventos de ciclo de vida de FastAPI para gestionar la conexión:
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)
Manejo de tipos BSON vs JSON
Los endpoints de FastAPI que proporcionan datos JSON a MongoDB podrían contener tipos ObjectId y Binary, que no cuentan con soporte nativo en JSON.
Puedes serializar ObjectId de varias formas:
Usar IDs basados en cadenas: Reemplaza
ObjectIdcon valores de cadena compatibles con JSON para campos_id. Este enfoque puede funcionar bien para nuevas aplicaciones, pero puede no ser adecuado si tienes datos existentes.Conversión automática: Convertir los valores de
ObjectIda representaciones en string al serializar a JSON y analizar los strings de nuevo aObjectIdal procesar datos entrantes.Integración Pydantic: Utiliza las anotaciones de tipo de Pydantic para gestionar la conversión automática, como se demuestra en el tipo
PyObjectIdde este tutorial.Mapeadores de Documentos de Objetos (ODMs): Utilice un ODM como Beanie, que supone que los campos
_idutilizanObjectIdpor defecto y gestiona automáticamente la serialización y deserialización.
Modelado de datos
Separe el esquema de su base de datos del esquema de su API para mantener la flexibilidad. Esto permite modificar las estructuras de los documentos de MongoDB sin cambiar su interfaz de API.
Proporcione una clase de Pydantic como response_model para su operación de ruta para convertir, validar, documentar y filtrar los campos de los datos BSON devueltos. El siguiente ejemplo de código muestra cómo 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}'" )
Más recursos
Para obtener más información sobre la integración de FastAPI, consulta los siguientes recursos:
- Generador de aplicaciones FastAPI Full Pila de MongoDB
Presentación de la entrada de blog sobre la pila FARM (FastAPI, React y MongoDB)
Para obtener soporte o contribuir a la MongoDB Community, consulte la MongoDB Developer Community.