La validación de datos y la gestión de archivos son aspectos cruciales en cualquier aplicación web, especialmente cuando se manejan grandes volúmenes de datos o se requiere una interacción constante con los usuarios, como en el caso de la carga y descarga de archivos. Al utilizar FastAPI, se pueden aprovechar herramientas como Pydantic para realizar una validación avanzada de los datos, asegurando que no solo estén en el formato correcto, sino que también cumplan con la lógica empresarial y las restricciones que se definan. Pydantic, gracias a sus potentes validadores, ofrece una forma robusta y flexible de manejar tanto la validación como la serialización de datos en las aplicaciones desarrolladas con FastAPI.
Al trabajar con archivos, FastAPI también simplifica el proceso, permitiendo a los desarrolladores manejar tanto las cargas como las descargas de archivos de manera eficiente y con un mínimo esfuerzo. Este flujo de trabajo es fundamental en muchas aplicaciones modernas, ya sea para la carga de avatares de usuarios, la descarga de informes o el procesamiento de archivos de datos.
El primer paso al trabajar con archivos en FastAPI es crear los endpoints adecuados para la carga de archivos. A través de las clases File y UploadFile de FastAPI, es posible gestionar estos archivos de manera eficiente. La clase UploadFile es especialmente útil, ya que proporciona una interfaz asíncrona y maneja los archivos grandes de manera que no agoten la memoria del servidor al almacenarlos temporalmente en el disco. Un ejemplo básico de cómo cargar un archivo sería el siguiente:
Este endpoint permite que el usuario cargue un archivo y devuelve simplemente el nombre del archivo. Sin embargo, para procesar el archivo de manera adecuada, se debe guardar en el servidor. A continuación, se muestra cómo se puede guardar un archivo subido en un directorio específico dentro del servidor:
Este fragmento de código guarda el archivo subido en el directorio uploads del servidor utilizando la función copyfileobj de shutil. Es importante, en un entorno de producción, tener en cuenta la gestión de excepciones, especialmente al tratar con archivos grandes, ya que podrían causar problemas de rendimiento o incluso fallos en el servidor.
El manejo de descargas de archivos en FastAPI es igualmente sencillo gracias a la clase FileResponse, que permite servir archivos al cliente de forma eficiente, incluso para archivos de gran tamaño. A continuación se muestra cómo definir un endpoint para descargar archivos:
Este endpoint sirve el archivo solicitado desde el directorio uploads. Si el archivo no se encuentra, se lanza una excepción HTTP 404. FileResponse maneja de manera automática el tipo de contenido del archivo, lo que facilita su descarga sin tener que preocuparse por configuraciones adicionales.
Sin embargo, la gestión de archivos no se limita solo a su carga y descarga. En aplicaciones de mayor escala, es recomendable usar sistemas de almacenamiento dedicados como Amazon S3, Google Cloud Storage o Azure Blob Storage, que ofrecen soluciones de almacenamiento escalables y seguras. Además, es fundamental establecer estrategias de limpieza o archivado para gestionar el ciclo de vida de los archivos almacenados, evitando que el servidor se sature de archivos innecesarios o antiguos.
La programación asíncrona, una característica central de FastAPI, también juega un papel importante en la eficiencia de las aplicaciones web. Con el uso de asyncio, se pueden manejar múltiples tareas concurrentemente, lo que es especialmente útil para operaciones de entrada/salida, como las interacciones con bases de datos o la gestión de archivos. Al escribir código no bloqueante, las aplicaciones pueden realizar múltiples operaciones sin detenerse, mejorando así su rendimiento y capacidad de respuesta.
Por ejemplo, al implementar una operación simple en dos endpoints, uno síncrono y otro asíncrono, se puede observar cómo la programación asíncrona mejora la eficiencia:
La diferencia entre los dos endpoints es que el primero bloquea el hilo de ejecución mientras espera, mientras que el segundo puede continuar con otras tareas mientras espera, mejorando la capacidad de la aplicación para manejar múltiples solicitudes simultáneamente sin demora.
Es importante que el lector comprenda que el uso de operaciones asíncronas no solo mejora la eficiencia de la aplicación, sino que también facilita la escalabilidad, permitiendo que el servidor maneje un mayor volumen de tráfico sin comprometer su rendimiento. Además, integrar sistemas de almacenamiento eficientes y bien gestionados, junto con una programación asíncrona adecuada, son prácticas fundamentales para construir aplicaciones rápidas y robustas.
¿Cómo manejar relaciones entre datos en bases de datos NoSQL como MongoDB?
En la integración de bases de datos NoSQL con aplicaciones modernas, como las desarrolladas con FastAPI, uno de los aspectos cruciales es la gestión de relaciones entre los diferentes documentos o entidades. MongoDB, al ser una base de datos NoSQL, se distingue de las bases de datos relacionales principalmente por su modelo de datos flexible y sin esquema fijo. Esto presenta tanto oportunidades como desafíos a la hora de trabajar con relaciones entre los datos. A continuación, exploramos dos enfoques comunes para manejar relaciones entre datos: embedding (inclusión de datos dentro de un solo documento) y referencing (referencias a otros documentos).
En primer lugar, es importante destacar que MongoDB no ofrece soporte directo para joins ni claves foráneas, características fundamentales en bases de datos relacionales. En lugar de ello, la estructura de los datos es flexible y puede adoptar varias formas, dependiendo de las necesidades específicas del sistema y la naturaleza de los datos. Por tanto, comprender cómo manejar relaciones dentro de este modelo es esencial para evitar redundancias o complicaciones innecesarias en la arquitectura de la base de datos.
Embedding (Incorporación de datos dentro de un documento)
Una de las técnicas más comunes es embedding, en la que los datos relacionados se almacenan dentro de un único documento. Este enfoque es ideal para aquellos casos en los que los datos relacionados están fuertemente conectados y no se espera que cambien con frecuencia. Por ejemplo, si tenemos una colección de canciones y queremos almacenar información sobre el álbum al que pertenece cada canción, podemos almacenar los detalles del álbum dentro de cada documento de canción. Esta práctica mejora el rendimiento de lectura, ya que no es necesario realizar consultas adicionales para obtener la información relacionada.
Un ejemplo de esto es la representación de una canción y su álbum asociado en MongoDB:
En este caso, al almacenar un álbum dentro de un documento de canción, MongoDB facilita la recuperación de ambos datos en una única consulta. Esta estrategia es especialmente útil cuando los datos del álbum no cambian con frecuencia y se leen de forma conjunta con la canción.
Sin embargo, esta aproximación puede presentar problemas si la cantidad de datos embebidos se vuelve demasiado grande. Si un álbum tiene mucha información o si se almacena información en varios documentos (por ejemplo, si un álbum está relacionado con muchas canciones), esto puede generar un rendimiento deficiente, problemas de duplicación de datos o incluso superar los límites de tamaño de documento de MongoDB.
Referencing (Referencias entre documentos)
El otro enfoque común en MongoDB es referencing, que implica almacenar solo una referencia (como un ID) a otro documento en lugar de incrustar todos los datos. Este enfoque es más adecuado para relaciones muchos a muchos o muchos a uno, donde los datos relacionados pueden ser compartidos por varios documentos. En lugar de almacenar todos los detalles de un álbum dentro de cada canción, se almacena una referencia al ID del álbum correspondiente.
Este método permite mantener los documentos más pequeños y eficientes, ya que no hay duplicación de datos. Sin embargo, la principal desventaja es que las consultas para obtener los datos relacionados pueden volverse más complejas y lentas, ya que se requiere hacer varias consultas para obtener toda la información relacionada. Un ejemplo típico de uso de referencias es en el caso de las listas de reproducción, donde varias canciones pueden estar asociadas a diferentes listas de reproducción.
Para implementar un sistema de listas de reproducción, se podría definir un modelo en el que una lista de reproducción tenga una lista de IDs de canciones, como se muestra a continuación:
Luego, en la base de datos, se guardan solo los IDs de las canciones dentro de la lista de reproducción. Cuando el cliente necesite obtener la lista de canciones de una lista de reproducción, se realiza una consulta adicional para obtener los detalles de cada canción basada en los IDs almacenados.
Este enfoque es muy útil en casos donde los datos son dinámicos o pueden cambiar con frecuencia, como ocurre con las listas de reproducción. Aunque las consultas pueden volverse más lentas debido a la necesidad de hacer múltiples búsquedas, este enfoque ofrece mayor flexibilidad y escalabilidad en aplicaciones más grandes.
Consideraciones al elegir entre Embedding y Referencing
La elección entre embedding y referencing depende de las necesidades de la aplicación. Si los datos relacionados son pocos, tienden a no cambiar y se accede a ellos con frecuencia, embedding puede ser la mejor opción. Esto es especialmente cierto si se busca una respuesta rápida para las consultas y un modelo de datos sencillo. Sin embargo, si los datos relacionados son más grandes o se actualizan con frecuencia, referencing puede ser más adecuado, ya que ayuda a reducir la duplicación de datos y facilita la gestión de actualizaciones.
También es importante tener en cuenta que el uso de referencias puede requerir un enfoque más sofisticado para manejar las transacciones, ya que una actualización en un documento puede requerir modificaciones en otros documentos, lo que puede incrementar la complejidad de las operaciones.
Conclusión
En MongoDB, la gestión de relaciones se maneja a través de dos técnicas principales: embedding y referencing. Ambas tienen sus ventajas y desventajas, y la elección entre una u otra dependerá de los requisitos específicos de rendimiento, escalabilidad y flexibilidad de la aplicación. La clave está en entender las características de los datos y cómo se van a usar, ya que esta comprensión guiará la decisión sobre la mejor manera de estructurar las relaciones entre documentos.
Por último, cuando se implementan relaciones en bases de datos NoSQL como MongoDB, es esencial considerar la consistencia y el rendimiento de las consultas, especialmente en escenarios con alta concurrencia. Además, las actualizaciones atómicas y la gestión de dependencias entre documentos son aspectos cruciales que deben ser gestionados cuidadosamente, sobre todo si se opta por la estrategia de referencing.
¿Cómo optimizar el rendimiento de las aplicaciones FastAPI?
Integrar un perfilador en tu aplicación FastAPI es solo el primer paso para identificar cuellos de botella en el código y optimizar el rendimiento. Sin embargo, para mejorar realmente la eficiencia, es necesario adoptar diversas estrategias adicionales que maximicen el uso de los recursos disponibles. A continuación, exploramos varias técnicas para optimizar el rendimiento de las aplicaciones FastAPI.
Una de las primeras estrategias que se debe considerar es la programación asincrónica. FastAPI está construido sobre la biblioteca Starlette, la cual soporta manejadores de solicitudes asincrónicas usando las palabras clave async y await. Esto permite que la aplicación maneje solicitudes concurrentes de manera eficiente, maximizando la utilización de la CPU y las operaciones de entrada/salida (I/O). Al aprovechar la programación asincrónica, puedes reducir los tiempos de respuesta y mejorar la escalabilidad de tu aplicación, especialmente cuando se manejan muchas solicitudes simultáneas.
En relación con la escalabilidad, otra técnica importante es aumentar el número de trabajadores de Uvicorn. Uvicorn es un servidor ASGI que permite distribuir las solicitudes entrantes entre múltiples procesos. Aunque esta técnica puede ser útil en ciertos escenarios, no siempre es la solución ideal. Para operaciones que dependen principalmente de I/O, la programación asincrónica ya reduce significativamente el uso de la CPU, lo que deja a los trabajadores adicionales inactivos. Por ello, antes de agregar más trabajadores, es importante monitorear el uso de la CPU del proceso principal y verificar si realmente es necesario escalar.
El uso de cachés es otra técnica fundamental para optimizar el rendimiento de las aplicaciones FastAPI. Implementar mecanismos de caché permite almacenar y reutilizar datos que son frecuentemente accesados, lo que reduce la necesidad de realizar consultas a bases de datos o cálculos costosos. FastAPI se puede integrar fácilmente con bibliotecas dedicadas a la implementación de cachés, lo que facilita la mejora en el tiempo de respuesta y reduce la carga en los recursos del sistema.
Además, la implementación de la limitación de tasa (rate limiting) es una estrategia esencial para proteger la aplicación contra abusos y evitar la sobrecarga de recursos. La limitación de tasa regula la cantidad de solicitudes que un cliente puede hacer en un tiempo determinado. Esta técnica es especialmente útil para evitar ataques como el de denegación de servicio (DoS) y asegurar que la aplicación mantenga un rendimiento adecuado bajo condiciones de alto tráfico.
Para implementar la limitación de tasa en FastAPI, se puede usar la librería slowapi. Este paquete permite limitar las solicitudes basadas en la dirección IP del cliente, aunque también es posible crear una función personalizada que controle la tasa según las credenciales del usuario. Después de configurar el limitador, se pueden aplicar restricciones a los endpoints específicos utilizando decoradores. Por ejemplo, se podría establecer un límite de dos solicitudes por minuto para un endpoint determinado, lo que garantizaría que un cliente no realice peticiones en exceso en un corto período de tiempo. Es posible añadir un límite global a toda la aplicación configurando un middleware, lo que facilita la implementación de políticas de limitación a nivel global.
Otra característica avanzada que puede mejorar la eficiencia de una aplicación FastAPI son las tareas en segundo plano (background tasks). Las tareas en segundo plano permiten delegar operaciones intensivas en recursos a procesos separados, de manera que la aplicación siga siendo receptiva y pueda manejar varias solicitudes simultáneamente. Este enfoque es útil especialmente para procesos largos o costosos que no deben bloquear el ciclo principal de solicitud-respuesta. Implementar tareas en segundo plano mejora la escalabilidad y la eficiencia general de la aplicación.
Finalmente, es fundamental realizar pruebas de rendimiento y monitorear constantemente el comportamiento de la aplicación bajo diferentes condiciones de tráfico. Configurar un perfilador para identificar posibles cuellos de botella es solo el primer paso; las pruebas de estrés y carga son esenciales para asegurar que la aplicación pueda manejar el tráfico esperado sin comprometer la experiencia del usuario.
Es importante tener en cuenta que la optimización del rendimiento no es un proceso único ni definitivo. Las aplicaciones evolucionan y los patrones de tráfico cambian con el tiempo, por lo que es necesario revisar y ajustar regularmente las estrategias implementadas. Además, aunque se puede mejorar el rendimiento a nivel de código, no debemos olvidar que la infraestructura subyacente, como la base de datos, el servidor web y la red, también juega un papel crucial en la capacidad de la aplicación para escalar y manejar grandes volúmenes de tráfico.
¿Cómo preparar y desplegar aplicaciones FastAPI con HTTPS?
Para comenzar con una aplicación FastAPI básica, lo primero que debemos asegurarnos es que tenemos un módulo FastAPI mínimo con al menos un endpoint. Creamos un proyecto nuevo llamado "Live Application", generando una carpeta de proyecto llamada live_application con una subcarpeta app que contiene el módulo main.py como sigue:
Además, es necesario contar con una versión de FastAPI superior a 0.111.0 en el entorno. Para ello, ejecutamos el siguiente comando desde la línea de comandos:
Si ya tienes FastAPI instalado, asegúrate de tener la última versión ejecutando:
Una vez completada la instalación o actualización, podemos comenzar con la receta. Para ello, simplemente ejecutamos el siguiente comando:
Verás información detallada en la terminal, la cual te ayudará a verificar que todo esté funcionando correctamente. El primer mensaje que verás será algo como esto:
Con el comando fastapi dev, no especificamos el argumento app.main:app como se solía hacer con el comando uvicorn. Esto se debe a que la CLI de FastAPI detecta automáticamente el objeto FastAPI en el código según un conjunto de rutas predeterminadas. A continuación, verás mensajes sobre la construcción del servidor, la detección de los paquetes y módulos necesarios:
El siguiente conjunto de mensajes indicará el modo de ejecución y las direcciones principales como sigue:
Este mensaje indica que la aplicación está funcionando en modo de desarrollo, lo que significa que el servidor se reiniciará automáticamente cuando haya actualizaciones en el código. El servidor estará disponible en la dirección local 127.0.0.1. Alternativamente, podemos ejecutar el servidor en modo producción con el siguiente comando:
Esto no habilitará la recarga automática y la aplicación será visible solo en la red local de la máquina que está alojando el servidor. Existen otros comandos básicos para ejecutar tu aplicación FastAPI con diferentes configuraciones, que se pueden consultar en la documentación oficial.
Un aspecto importante a considerar es que la CLI de FastAPI depende del comando uvicorn para ejecutar el servidor, por lo que algunos de sus parámetros son similares. Por ejemplo, si deseas ejecutar el servicio en un puerto diferente al 8000, puedes usar el parámetro --port. De igual manera, para especificar la dirección del host, puedes usar el parámetro --host. Para ver la documentación completa de los parámetros disponibles, puedes ejecutar:
Si deseas que la aplicación sea visible en toda la red local, puedes pasar la dirección 0.0.0.0 al parámetro --host de la siguiente manera:
Habilitando HTTPS en aplicaciones FastAPI
Las aplicaciones web necesitan seguridad, y HTTPS (Protocolo Seguro de Transferencia de Hipertexto) es una forma básica de asegurar la comunicación entre los clientes y el servidor. HTTPS cifra los datos enviados a través de la red, previniendo accesos no autorizados y modificaciones. En este apartado aprenderemos cómo habilitar HTTPS en aplicaciones FastAPI para pruebas locales, utilizando mkcert para generar un certificado SSL/TLS y brindando algunas recomendaciones para la implementación en producción.
Para comenzar, se debe tener cierta comprensión de HTTPS y los certificados SSL/TLS. Desde la perspectiva del consumidor, puedes encontrar una visión general útil sobre cómo funciona HTTPS en este enlace: https://howhttps.works/. Utilizaremos una aplicación ya existente como ejemplo, aunque también puedes aplicar este procedimiento a tu propia aplicación.
En primer lugar, necesitamos instalar mkcert, que es una herramienta sencilla para crear certificados SSL/TLS locales. La instalación varía dependiendo del sistema operativo, y las instrucciones pueden encontrarse aquí: https://github.com/FiloSottile/mkcert#installation. Una vez instalado, ejecuta el siguiente comando para verificar que mkcert funciona correctamente:
Con la instalación completa, podemos comenzar a generar los certificados. El primer paso es permitir que nuestro navegador confíe en los certificados generados localmente por mkcert. Esto se puede lograr con el siguiente comando:
Este comando agregará un certificado local en el almacén de confianza de tu sistema, permitiendo que los navegadores lo reconozcan como una fuente confiable de certificados. Luego, generaremos los certificados y la clave privada que el servidor utilizará para ciertos rangos de dominios con el siguiente comando:
Este comando generará dos archivos: example.com+5-key.pem para la clave privada y example.com+5.pem para el certificado. Es importante tener en cuenta que, por razones de seguridad, nunca debes incluir los certificados ni las claves en el historial de Git. Agrega la extensión .pem a tu archivo .gitignore para evitar que se suban accidentalmente.
A continuación, debemos proporcionarle al servidor la clave y el certificado al momento de iniciar el servicio. Actualmente, el comando fastapi no permite pasar estos archivos directamente, por lo que debemos iniciar el servidor utilizando uvicorn de la siguiente forma:
Este comando iniciará el servidor con el certificado y la clave proporcionados. Para verificar que la configuración funcione, abre tu navegador y ve a la dirección local. Si todo está bien configurado, verás un icono de candado en la barra de direcciones, indicando que la conexión es HTTPS. Si intentas acceder a la misma dirección con HTTP (es decir, http://localhost:443), recibirás un error.
Es posible mejorar esta configuración añadiendo una redirección automática de HTTP a HTTPS utilizando un middleware proporcionado por FastAPI. Para ello, debes modificar tu archivo main.py de la siguiente forma:
Esto asegurará que cualquier solicitud HTTP sea automáticamente redirigida a HTTPS, mejorando la seguridad de la aplicación.
¿Cómo organizar tu código en FastAPI usando routers y endpoints?
En FastAPI, uno de los aspectos clave para el desarrollo eficiente y mantenible de aplicaciones web es la organización adecuada de los endpoints mediante routers. Los routers no solo permiten una mayor modularidad en el código, sino que también facilitan su escalabilidad y comprensión a largo plazo.
Al comenzar con FastAPI, es común que todo el código se concentre en un solo archivo, pero a medida que el proyecto crece, este enfoque se vuelve insostenible. Para gestionar múltiples endpoints, la mejor práctica consiste en organizar el código en módulos separados, cada uno enfocado en una parte específica de la aplicación. Esto se logra mediante el uso de routers.
Un router en FastAPI es una forma de agrupar endpoints relacionados en un solo lugar, lo que hace que el código sea más limpio y organizado. Por ejemplo, si tienes operaciones relacionadas con productos y usuarios, puedes tener un router para cada uno, lo que te permitirá mantener el código modular y fácil de mantener.
Imagina que estamos creando una aplicación para una librería online. En lugar de definir todos los endpoints en un único archivo, podemos crear diferentes routers para gestionar libros, autores, y categorías de productos. Por ejemplo, un archivo llamado router_libros.py podría contener todos los endpoints relacionados con libros, mientras que router_autores.py podría incluir aquellos que manejan información sobre autores.
Para definir un router en FastAPI, se utiliza el APIRouter, que actúa como un contenedor para los endpoints. A continuación se muestra cómo se puede definir un router básico para obtener información sobre libros en un sistema de librería:
En este fragmento de código, hemos definido un endpoint que responde a las solicitudes GET en la ruta /libros/{libro_id}. El parámetro libro_id en la URL se extrae dinámicamente y se pasa a la función obtener_libro, que responde con un JSON que contiene detalles sobre el libro solicitado.
Una vez que hayas creado tu router, es necesario incluirlo en la aplicación principal de FastAPI. Esto se realiza utilizando el método include_router:
De este modo, el router router_libros se incorpora al servidor principal de FastAPI, permitiendo que todos los endpoints definidos en él estén disponibles para ser utilizados.
Un aspecto crucial de FastAPI es su capacidad de generar documentación interactiva automáticamente. Cuando se corre la aplicación, FastAPI proporciona dos interfaces para explorar y probar la API: Swagger UI y Redoc. Estas herramientas permiten a los desarrolladores y usuarios interactuar con los endpoints sin necesidad de escribir código adicional. Para acceder a la documentación de la API, simplemente navega a las URLs correspondientes en tu navegador:
-
Swagger UI:
http://127.0.0.1:8000/docs -
Redoc:
http://127.0.0.1:8000/redoc
Además de los endpoints básicos, FastAPI facilita la validación automática de los datos gracias a los type hints. Estos permiten que, si un parámetro en la URL no cumple con el tipo esperado (por ejemplo, un int cuando se espera un str), FastAPI responderá con un error claro, evitando problemas en el manejo de datos. Este tipo de validación es esencial en aplicaciones grandes, ya que asegura que los datos que recibe la API estén en el formato adecuado y reduce la posibilidad de errores durante el procesamiento de solicitudes.
Al desarrollar APIs más complejas, puede ser necesario manejar parámetros tanto en la ruta (path parameters) como en la cadena de consulta (query parameters). FastAPI facilita esta tarea, ya que automáticamente extrae los valores de los parámetros de la URL y los pasa a las funciones correspondientes. Además, permite realizar validaciones de manera eficiente, lo cual mejora la experiencia del desarrollador y garantiza la calidad del servicio.
Una vez que se define un endpoint, ya sea para obtener información de un libro, de un autor, o de cualquier otra entidad en el sistema, puedes probarlo usando herramientas como Swagger UI o Postman. Si bien Swagger UI es una herramienta rápida y efectiva para probar tu API en el navegador, Postman es una opción más robusta y profesional para escenarios más complejos. Con Postman, puedes crear y gestionar pruebas más detalladas, como solicitudes con autenticación, manipulación de headers, entre otras características avanzadas.
Finalmente, algo importante que hay que destacar es la capacidad de FastAPI para manejar peticiones de manera asíncrona. Esto significa que, cuando una solicitud está siendo procesada, el servidor puede continuar atendiendo otras solicitudes sin necesidad de esperar a que la primera termine. Esta característica es vital para aplicaciones con gran volumen de tráfico o que requieren procesamiento intensivo, ya que mejora significativamente el rendimiento y la capacidad de respuesta.

Deutsch
Francais
Nederlands
Svenska
Norsk
Dansk
Suomi
Espanol
Italiano
Portugues
Magyar
Polski
Cestina
Русский