La documentación de API de alta calidad mejora la satisfacción del cliente, especialmente en la arquitectura sin servidor, donde las funciones Lambda sirven a la API. Documentar estas API siempre ha parecido como escribir una novela con una pluma. Al menos, así era hasta ahora, cuando Powertools for AWS lanzó su utilidad de documentación OpenAPI.
Esta publicación presenta un método para generar documentación OpenAPI para API basadas en funciones Python Lambda, utilizando Powertools para AWS Lambda y Pydantic.
En la próxima publicación, analizaremos cómo automatizar este proceso y agregarlo al flujo de trabajo de CI/CD del servicio como puerta de entrada a la producción y la publicación de la documentación.
Tabla de contenido
El caso de la documentación de API
Cuando diseño funciones que requieren cambios en la API, las documento.
Creo firmemente en adoptar el enfoque API-first . Allen Helton , un héroe de AWS serverless, ha escrito una excelente publicación sobre los méritos del enfoque API-first. Permite que sus clientes de API, ya sean internos o externos, desarrollen y planifiquen su integración con su API sin quedar bloqueados hasta que publique la nueva API. Les envía la documentación de la API y los deja trabajar.
Un enfoque que prioriza las API significa que, para cualquier proyecto de desarrollo, sus API se tratan como "ciudadanos de primera clase". - Swagger.io
La documentación de API también es útil para comprender en todo momento qué ofrece su servicio de principio a fin. Es excelente para integraciones futuras, desarrollo de nuevas funciones e incorporación de nuevos miembros al equipo.
OpenAPI - El rey de los estándares
OpenAPI se ha convertido en el formato estándar para describir API.
La especificación OpenAPI (anteriormente, la especificación Swagger) es un formato de descripción de API para API REST. Un archivo OpenAPI le permite describir toda su API - Swagger.io .
Es un archivo simple con formato JSON o YML que nos permite describir nuestra API REST y su:
Puntos finales disponibles
Operaciones en cada punto final
Parámetros de operación: Entrada y salida para cada operación
Métodos de autenticación
Organice los puntos finales por etiquetas o grupos e incluso genere una solicitud de muestra.
Swagger.io es una herramienta que te permite visualizar este archivo de documentación.
Puede ver una demostración en vivo del formato para un servicio ficticio aquí , y se parece a esto:
Ahora que entendemos cómo queremos documentar nuestras API, hablemos de adaptar este proceso a nuestras API sin servidor respaldadas por funciones Lambda.
Generación de documentación de API
Cubramos varios métodos para generar documentación de API.
En mi opinión, el mejor método para generar documentación de API basada en Python es crearla a partir del código del servicio. Utilizo Pydantic para definir esquemas de entrada y respuesta, y tiene la opción nativa de exportar los esquemas a un formato OpenAPI, lo que es una gran ventaja en mi opinión. Por lo tanto, la integración con esta herramienta es necesaria para cualquier solución que elijamos.
La primera opción viene de forma nativa de API Gateway.
API Gateway tiene una característica interesante. Una vez implementado, puede exportar la documentación de OpenAPI desde la consola o a través de la API como se describe aquí . Sin embargo, no hay compatibilidad con Pydantic y muchos esquemas de detalles más finos (entrada o salida) no se configuran fácilmente, ya que usted mismo define el esquema JSON y habilita la validación de solicitudes. Y, por último, no se crea a partir de nuestro código de controlador, sino a partir del código de infraestructura, lo cual es bueno pero imperfecto.
Por lo tanto, si bien es una característica interesante, se necesita más. Repasemos otro método.
La segunda opción proviene de marcos como FastAPI.
FastAPI es un marco web moderno, rápido (de alto rendimiento) para crear API con Python 3.8+: https://fastapi.tiangolo.com/
La mayoría de estos marcos y herramientas de Python, como FastAPI, Flask-RESTPlus/Flask-RESTx, Django REST Framework y Connexion, están diseñados para crear aplicaciones web y API que escuchan en un socket las solicitudes HTTP entrantes.
Centrémonos en FastAPI.
FastAPI admite esquemas de Pydantic para describir cargas útiles y generar documentación de OpenAPI directamente desde el código. Este enfoque simplifica el proceso de documentación y lo mantiene sincronizado con el código.
Sin embargo, básicamente estás ejecutando un servidor web en Lambda que abre un socket para escuchar las solicitudes HTTP entrantes, algo que el servicio Lambda ya hace por ti. Es un marco basado en servidor con implicaciones negativas en un arranque en frío, el tamaño del archivo ZIP de Lambda y la latencia. Y si bien PUEDES hacerlo, no creo que DEBAS hacerlo.
En mi opinión, necesitamos un marco nativo sin servidor para proporcionar documentación OpenAPI generada a partir del código del controlador. Debe ser rápido y coincidir con el modelo de invocación de Lambda y, como tal, no debe abrir sockets por sí solo.
Veamos cómo podemos lograrlo.
Documentación de OpenAPI sin servidor
Nuestro objetivo es generar una documentación OpenAPI para una API sin servidor que consta de un API Gateway y una función Lambda. Definiremos el esquema de carga útil de entrada HTTP y TODAS las posibles respuestas HTTP: sus códigos y la carga útil JSON completa. Usaremos Pydantic para definir todos los esquemas.
La documentación de OpenAPI se servirá bajo un nuevo punto final de API: '/swagger'.
En la próxima publicación del blog, analizaremos cómo exportar la documentación y automatizar todo este proceso.
Ahora que entendemos el objetivo, escribamos algo de código.
Introducción al manejador de eventos de Powertools
Usamos la biblioteca Powertools for AWS Lambda . Powertools for Lambda es la biblioteca sin servidor a la que recurrir para la observabilidad, el registro, la idempotencia, la validación de entradas y mucho más.
Utilizaremos la utilidad del controlador de eventos de Powertools.
La utilidad de controlador de eventos proporciona un enrutamiento liviano para reducir el código repetitivo para las URL de API REST/HTTP API, ALB y funciones Lambda de API Gateway. Funciona con microfunciones (una o algunas rutas) y funciones monolíticas (todas las rutas). Lo más interesante es que es compatible con OpenAPI y validación de datos para solicitudes/respuestas con esquemas Pydantic.
La documentación de OpenAPI es una función relativamente nueva. Proporciona un punto final "/swagger" en su API Gateway que genera una documentación de OpenAPI.
Implementemos el controlador de eventos y la validación de datos en un servicio real.
Usaremos mi proyecto de plantilla de libro de recetas de AWS Lambda y agregaremos compatibilidad con la documentación de OpenAPI. El libro de recetas es un proyecto de plantilla que le permite comenzar a trabajar sin servidor con tres clics y tiene todas las mejores prácticas y utilidades que requiere un servicio sin servidor de nivel de producción.
Comencemos con la configuración de la infraestructura.
Infraestructura de puntos finales de OpenAPI
Los documentos oficiales tienen ejemplos de código SAM, pero yo uso AWS CDK.
A continuación se muestra una función para agregar a su construcción de API REST de CDK.
Por diseño, debe seleccionar un controlador Lambda para responder a las llamadas HTTP GET '/swagger' y generar la documentación OpenAPI. Necesitamos conectar la función Lambda que utiliza la utilidad del controlador de eventos.
Debe asignar tres puntos finales 'GET' (/swagger, /swagger.css, /swagger.js) a esa función para la generación de swagger.
En la línea 5, la función recibe el objeto de puerta de enlace de API REST para agregar los nuevos puntos finales y la clase de función Lambda que servirá a estos puntos finales.
En las líneas 7 a 14, agregamos los tres puntos finales y les adjuntamos la función Lambda con un comando HTTP GET.
Puedes encontrar el código completo aquí .
Código del controlador de eventos
Ahora que tenemos toda la infraestructura configurada, agreguemos el código del controlador de eventos y comencemos a documentar nuestra API.
En la línea 3, creamos el solucionador de puerta de enlace de API del controlador de eventos y habilitamos la validación para obtener los eventos de entrada y las validaciones de respuesta de salida (usando Pydantic ).
En la línea 4, habilitamos la generación de OpenAPI a través del punto final '/swagger' y pasamos un título al documento generado. Según la documentación , debe habilitar la validación para obtener la definición completa de OpenAPI.
Puedes encontrar el código completo aquí .
Código del controlador Lambda
Escribamos el código del controlador Lambda y documentémoslo.
Documentaremos el punto final HTTP POST '/api/orders', que crea un nuevo pedido de cliente.
Aquí están sucediendo muchas cosas, pero es bastante simple. Vamos a agregar la mayor cantidad posible de información de OpenAPI. Describiremos la API específica, su descripción, los esquemas de entrada para la carga útil del cuerpo HTTP JSON y todos los esquemas de respuestas HTTP posibles con Pydantic.
En la línea 8, importamos el controlador de eventos que inicializamos en el archivo anterior.
En la línea 13, iniciamos la definición de la aplicación. Primero, marcamos esta API como HTTP POST.
En la línea 14, configuramos la API para responder a la ruta '/API/orders/.'
En la línea 15, establecemos la descripción de la API que aparecerá en la documentación de OpenAPI.
En las líneas 18 a 31, definimos todas las respuestas de la API.
En las líneas 19 a 22, definimos la respuesta HTTP 200 OK. Así es como podemos controlar todas las definiciones de respuesta HTTP. Tenga en cuenta que si no define estas respuestas, el controlador de eventos las generará automáticamente para usted e incluirá las respuestas 422 y 200, pero no la 501. La 422 es una respuesta incorporada de la función de validación de entrada. La respuesta 200 se crea utilizando los tipos de valor de retorno del controlador que definimos en la línea 35: el esquema Pydantic " CreateOrderOutput ".
En las líneas 23 a 26, definimos la respuesta de validación de entrada HTTP con un código HTTP 422. Usamos el esquema de Pydantic ' InvalidApiRequest ' para describirlo.
En las líneas 27 a 30, hacemos lo mismo para HTTP 501.
En la línea 32, etiquetamos esta API como parte de un grupo llamado "CRUD". Cuando tienes varias API, las etiquetas facilitan la presentación de las API en varias sublistas que en una sola lista larga.
En la línea 39, definimos la función de entrada para el controlador. El solucionador llamará a la subfunción del controlador de eventos correcta según la ruta HTTP y el comando. Lea más sobre esto aquí . En nuestro caso, todas las llamadas se dirigirán a la función que definimos en las líneas 13 a 36.
En las líneas 34 y 35, usamos la sugerencia de tipo para definir la entrada que espera el controlador. Dado que habilitamos la validación de datos, una vez que ingresamos a la línea 36, tenemos un objeto Pydantic serializado y analizado en nuestras manos y no el evento regular como un diccionario. Usé las clases especiales de tipado de cuerpo y anotadas para indicarle al controlador de eventos que espera la clase ' CreateOrderInput ' en la carga útil del cuerpo y que es un diccionario JSON y no una cadena.
Tenga en cuenta que todas las solicitudes y respuestas de API tienen un esquema de Pydantic que las define. Puede encontrar todas las definiciones de esquemas de Pydantic aquí y aquí .
Puedes encontrar el código completo del controlador aquí .
Escribí este controlador y la lógica de acuerdo con mis conceptos de capas arquitectónicas, que también analicé en mi sesión de AWS re:invent 2023. Haga clic aquí para obtener más información.
Punto final OpenAPI en acción
Ahora, todo lo que queda es implementar nuestro código y acceder a nuestro punto final Swagger.
Se verá algo así como esto:
Tenga en cuenta que podemos hacer clic en los esquemas y ver la salida de la definición de Pydantic como un esquema OpenAPI adecuado, con las descripciones, restricciones y tipos.
También puedes ver una versión en vivo del swagger aquí:
Limitaciones
Me ha impresionado bastante esta nueva utilidad. Sin embargo, tiene algunas limitaciones.
Se puede solucionar pero requiere desarrollo por parte del equipo de Powertools o de la comunidad.
Por ejemplo, no se genera toda la especificación OpenAPI. Sin embargo, hay problemas abiertos en el repositorio y se solicita la ayuda de la comunidad, por lo que podría ser una primera contribución importante si desea probarlo.
Ahora, pasemos a la cuestión más importante.
Al momento de escribir esto, no hay soporte para la generación de OpenAPI si usas múltiples microfunciones; solo se admite lambda mono. He creado un problema en GitHub con una solución sugerida y agradecería que me dieran un visto bueno para que todo comience a funcionar.
Resumen
En esta publicación, vimos cómo Powertools para AWS puede ayudarlo a generar documentación OpenAPI a partir de su código de controlador. Permite a los desarrolladores ser dueños del código y su documentación y, lo más importante, cómo mantenerlos sincronizados constantemente.
Únase a mí en la próxima publicación, donde analizaré cómo puede llevar este enfoque aún más allá y agregar puertas importantes a su canalización de CI/CD para proteger esta valiosa sincronización entre el código y la documentación de la API.
Comments