Overview
FastAPI es un framework web Python asíncrono, moderno, de alto rendimiento y listo para producción, diseñado para crear API mediante sugerencias de tipos estándar de Python. En este tutorial, aprenderá a crear una aplicación CRUD completa que integra 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 ligero de inyección de dependencias Pythonic 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
Puede encontrar la aplicación de muestra completa para este tutorial en el repositorio de GitHub del proyecto de muestra MongoDB con FastAPI.
Requisitos previos
Asegúrate de tener instalados y configurados los siguientes componentes antes de comenzar este tutorial:
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
Instalar las dependencias necesarias
Tip
Activar un entorno virtual
Instalar las dependencias de Python en un entorno virtual permite instalar versiones de las bibliotecas para proyectos individuales. Antes de ejecutar cualquier comando, asegúrese de pip 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 inicie una nueva sesión de terminal, deberá restablecer esta variable de entorno. Puede usar direnv para simplificar 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 usa _id como identificador predeterminado para los documentos. Sin embargo, en Pydantic, los nombres de campo que empiezan con un guion bajo se consideran atributos privados y no se les pueden asignar valores directamente. Para solucionar esto, podemos nombrar el campo id en el modelo de Pydantic, pero con el alias _id para que se asigne 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 de StudentModel sin especificar un id. MongoDB genera automáticamente un _id al insertar 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 cómo se compara BSON con JSON, consulte el artículo JSON y BSON 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 StudentCollection clase se define para encapsular una lista de StudentModel instancias. El propósito de este endpoint es brindar protección contra el secuestro de JSON, donde un usuario malintencionado intenta acceder a datos confidenciales aprovechando la forma en que los navegadores gestionan las matrices JSON. Para más información, puede leer el artículo sobre el secuestro de JSON 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 |
| Eliminar un estudiante |
Estas rutas se definen 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 ver a todos los estudiantes y otra para ver a un estudiante individual, especificado 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 to_list() método; pero en una aplicación real, recomendamos utilizar los parámetros skip y limit en find para paginar sus 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 forma similar a una combinación de las rutas create_student y show_student. Recibe el id del estudiante que se va a actualizar y los nuevos datos en el cuerpo 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")
Eliminar 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
Vaya a http://:127.0.0.1 8000/docs. La siguiente imagen 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 punto final Show Student, puede 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, puede utilizar las siguientes herramientas para administrar las variables de entorno:
direnv: Carga automáticamente variables de entorno desde un archivo
.envrcal ingresar a un directoriopython-dotenv: carga variables de entorno desde un
.envarchivo dentro de su aplicación Pythonenvdir: 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 elija, agregue cualquier archivo que contenga secretos (como .env, .envrc o similares) a su archivo .gitignore para evitar que se confirmen 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: convierte
ObjectIdvalores en representaciones de cadenas al serializar en JSON y analiza cadenas nuevamente comoObjectIdal 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 (ODM): utilice un ODM como Beanie, que asume que los
_idcampos usanObjectIdde manera predeterminada y maneja automáticamente la serialización y la 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 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 de pila completa 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.