Chaining API Requests with API Gateway

Bobur Umurzokov

Bobur Umurzokov

May 23, 2023

Technology

A medida que aumenta el número de API que deben integrarse, gestionar la complejidad de las interacciones de las API se vuelve cada vez más desafiante. Al utilizar el API Gateway, podemos crear una secuencia de llamadas a API, lo que descompone los flujos de trabajo de las API en pasos más pequeños y manejables. Por ejemplo, en un sitio web de compras en línea, cuando un cliente busca un producto, la plataforma puede enviar una solicitud a la API de búsqueda de productos y luego enviar una solicitud a la API de detalles del producto para obtener más información sobre los productos. En este artículo, crearemos un plugin personalizado para el API Gateway Apache APISIX para manejar solicitudes de clientes que deben ser llamadas en secuencia.

Objetivos de aprendizaje

A lo largo del artículo aprenderás lo siguiente:

  • ¿Qué son las solicitudes encadenadas de API?
  • Ejemplo de llamadas secuenciales a API.
  • Cómo construir un plugin personalizado de pipeline-request para Apache APISIX.
  • Demostración del plugin pipeline-request.

Pipelining API requests with API Gateway

¿Qué es una solicitud encadenada de API y por qué la necesitamos?

Las solicitudes encadenadas de API (o solicitudes en pipeline, o llamadas secuenciales a API) son una técnica utilizada en el desarrollo de software para gestionar la complejidad de las interacciones de API donde el software requiere múltiples llamadas a API para completar una tarea. Es similar al procesamiento de solicitudes por lotes, donde agrupas múltiples solicitudes de API en una sola solicitud y las envías al servidor como un lote. Aunque pueden parecer similares, una solicitud en pipeline implica enviar una única solicitud al servidor que desencadena una secuencia de solicitudes de API que se ejecutan en un orden definido. Cada solicitud de API en la secuencia puede modificar los datos de la solicitud y la respuesta, y la respuesta de una solicitud de API se pasa como entrada a la siguiente solicitud de API en la secuencia. Las solicitudes en pipeline pueden ser útiles cuando un cliente necesita ejecutar una secuencia de solicitudes de API dependientes que deben ejecutarse en un orden específico.

En cada paso del pipeline, podemos transformar o manipular los datos de la respuesta antes de pasarlos al siguiente paso. Esto puede ser útil en situaciones donde los datos necesitan ser normalizados o transformados o filtrar datos sensibles antes de que se devuelvan al cliente. Puede ayudar a reducir la latencia general. Por ejemplo, una llamada a API puede realizarse mientras otra está esperando una respuesta, reduciendo el tiempo total necesario para completar el flujo de trabajo.

sequential API calls with API Gateway

Plugin personalizado de pipeline-request para Apache APISIX

Un API Gateway puede ser el lugar adecuado para implementar esta funcionalidad, ya que puede interceptar todas las solicitudes de la aplicación cliente y reenviarlas a los destinos previstos. Vamos a utilizar Apache APISIX, ya que es una solución de API Gateway de código abierto popular con un montón de plugins integrados. Sin embargo, al momento de desarrollar esta publicación, APISIX no tenía soporte oficial para el plugin de pipeline-request. Con el conocimiento de las capacidades de desarrollo de plugins personalizados de APISIX, decidimos introducir un nuevo plugin que pueda ofrecer la misma funcionalidad. Hay un repositorio en GitHub con el código fuente escrito en el lenguaje de programación Lua y una descripción del plugin pipeline-request.

Con este plugin, puedes especificar una lista de API upstream que deben ser llamadas en secuencia para manejar una única solicitud del cliente. Cada API upstream puede modificar los datos de la solicitud y la respuesta, y la respuesta de una API upstream se pasa como entrada a la siguiente API upstream en el pipeline. El pipeline puede definirse en una configuración de Ruta, y también puedes definir órdenes para las URL de las API cuando el pipeline debe ejecutarlas.

Entendamos el uso de este plugin con un ejemplo. Supongamos que tienes dos API: una que realiza solicitudes GET /credit_cards para recuperar información de tarjetas de crédito y otra que recibe los datos de la respuesta anterior en el cuerpo de una solicitud POST /filter y luego filtra los datos sensibles (como el número de tarjeta de crédito y la fecha de vencimiento) antes de devolver la respuesta al cliente. Debido a que el endpoint de la API de tarjetas de crédito devuelve información sensible que no debe exponerse a partes no autorizadas. El siguiente diagrama ilustra el flujo general de datos:

sequential API calls with API Gateway to filter

  1. Cuando un cliente realiza una solicitud al endpoint de la API de tarjetas de crédito del API Gateway para recuperar toda la información de las tarjetas de crédito, el API Gateway reenvía una solicitud para recuperar los datos de las tarjetas de crédito del servicio backend de tarjetas de crédito.
  2. Si la solicitud es exitosa y devuelve datos de tarjetas de crédito, entonces pasa al siguiente paso en el pipeline, que es el servicio de seguridad.
  3. Cuando se recibe la respuesta filtrada del servicio de seguridad, se devuelve la respuesta combinada al cliente.

Demostración del plugin pipeline-request

Para esta demostración, vamos a aprovechar otro proyecto de demostración preparado en GitHub, donde puedes encontrar todos los ejemplos de comandos curl utilizados en este tutorial, ejecutar APISIX y habilitar un plugin personalizado sin configuración adicional con un archivo Docker compose.yml.

Requisitos previos

  • Docker se utiliza para instalar etcd y APISIX en contenedores.
  • curl se utiliza para enviar solicitudes a la API de administración de APISIX. También puedes usar herramientas fáciles como Postman para interactuar con la API.

Paso 1: Instalar y ejecutar APISIX y etcd

Puedes instalar fácilmente APISIX y etcd ejecutando docker compose up desde la carpeta raíz del proyecto después de bifurcar/clonar el proyecto. Puedes notar que hay un volumen ./custom-plugins:/opt/apisix/plugins:ro especificado en el archivo docker-compose.yml. Esto monta el directorio local ./custom-plugins, donde se encuentra nuestro archivo pipeline-request.lua con la implementación del plugin personalizado, como un volumen de solo lectura en el contenedor de docker en la ruta /opt/apisix/plugins. Esto permite agregar plugins personalizados a APISIX en tiempo de ejecución (esta configuración solo es aplicable si ejecutas APISIX con docker).

Paso 2: Crear la primera Ruta con el plugin pipeline-request

Una vez que APISIX esté en ejecución, usamos el comando cURL que se utiliza para enviar una solicitud HTTP PUT a la API de administración de APISIX en el endpoint /routes para crear nuestra primera ruta que escucha en la ruta URI /my-credit-cards.

curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/1' \
--header 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' \
--header 'Content-Type: application/json' \
--data-raw '{
   "uri":"/my-credit-cards",
   "plugins":{
      "pipeline-request":{
         "nodes":[
            {
               "url":"https://random-data-api.com/api/v2/credit_cards"
            },
            {
               "url":"http://127.0.0.1:9080/filter"
            }
         ]
      }
   }
}'

La parte importante de la configuración es la sección "plugins", que especifica que se debe usar el plugin "pipeline-request" para esta ruta de API. La configuración del plugin contiene un array "nodes", que define la secuencia de solicitudes de API que deben ejecutarse en el pipeline. Puedes definir una o varias API allí. En este caso, el pipeline consta de dos nodos: el primer nodo envía una solicitud a la API https://random-data-api.com/api/v2/credit_cards para recuperar datos de tarjetas de crédito, y el segundo nodo envía una solicitud a una API local en http://127.0.0.1:9080/filter para filtrar datos sensibles de la información de la tarjeta de crédito. La segunda API será simplemente una función sin servidor utilizando el plugin serverless-pre-function de APISIX. Actúa como un servicio backend para modificar la respuesta de la primera API.

Paso 3: Crear la segunda Ruta con el plugin serverless

A continuación, configuramos una nueva ruta con el ID 2 que maneja las solicitudes al endpoint /filter en el pipeline. También habilita el plugin serverless-pre-function existente de APISIX, donde especificamos una función Lua que debe ser ejecutada por el plugin. Esta función simplemente recupera el cuerpo de la solicitud de la respuesta anterior, reemplaza el campo del número de tarjeta de crédito y deja el resto de la respuesta sin cambios. Finalmente, establece el cuerpo de la respuesta actual al cuerpo de la solicitud modificado y envía una respuesta HTTP 200 de vuelta al cliente. Puedes modificar este script para adaptarlo a tus necesidades, como usar el cuerpo decodificado para realizar más procesamiento o validación.

curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/2' \
--header 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' \
--header 'Content-Type: application/json' \
--data-raw '
{
  "uri": "/filter",
  "plugins":{
    "serverless-pre-function": {
            "phase": "access",
            "functions": [
                "return function(conf, ctx)
                    local core = require(\"apisix.core\")
                    local cjson = require(\"cjson.safe\")

                    -- Obtener el cuerpo de la solicitud
                    local body = core.request.get_body()
                    -- Decodificar el cuerpo JSON
                    local decoded_body = cjson.decode(body)

                    -- Ocultar el número de tarjeta de crédito
                    decoded_body.credit_card_number = \"****-****-****-****\"
                    core.response.exit(200, decoded_body);
                end"
            ]
        }
    }
}'

Paso 3: Probar la configuración

Ahora es el momento de probar la configuración general. Con el siguiente comando curl, enviamos una solicitud HTTP GET al endpoint http://127.0.0.1:9080/my-credit-cards.

curl http://127.0.0.1:9080/my-credit-cards

Tenemos la ruta correspondiente configurada en el segundo paso para usar el plugin pipeline-request con dos nodos, esta solicitud desencadenará el pipeline para recuperar la información de la tarjeta de crédito del endpoint https://random-data-api.com/api/v2/credit_cards, filtrar los datos sensibles utilizando el endpoint http://127.0.0.1:9080/filter y devolver la respuesta modificada al cliente. Ver la salida:

{
   "uid":"a66239cd-960b-4e14-8d3c-a8940cedd907",
   "credit_card_expiry_date":"2025-05-10",
   "credit_card_type":"visa",
   "credit_card_number":"****-****-****-****",
   "id":2248
}

Como puedes ver, reemplaza el número de tarjeta de crédito en el cuerpo de la solicitud (en realidad, es la respuesta de la primera llamada a API en la cadena) con asteriscos.

Resumen

Hasta ahora, hemos aprendido que nuestro plugin personalizado de pipeline request para el API Gateway Apache APISIX nos permite definir una secuencia de llamadas a API como un pipeline en un orden específico. También podemos usar este nuevo plugin en combinación con los existentes para habilitar autenticación, seguridad y otras características de API Gateway para nuestros endpoints de API.

Recursos relacionados

Tags: