Tutorial: Desarrollo de una API de REST de API Gateway con integración no de proxy de Lambda - Amazon API Gateway

Tutorial: Desarrollo de una API de REST de API Gateway con integración no de proxy de Lambda

En este tutorial utilizaremos la consola de API Gateway para crear una API que permita a un cliente llamar a funciones de Lambda a través de la integración de Lambda no de proxy (conocida también como integración personalizada). Para obtener más información acerca de las funciones de AWS Lambda y de Lambda, consulte la Guía para desarrolladores de AWS Lambda.

Para facilitar el aprendizaje, elegimos una función de Lambda sencilla con una configuración de API mínima para guiarlo para desarrollar una API de API Gateway con la integración de Lambda personalizada. Cuando sea necesario, describiremos parte de la lógica. Para ver un ejemplo más detallado de la integración de Lambda personalizada, consulte Tutorial: Creación de una API de REST de calculadora con dos integraciones de servicios de AWS y una integración de Lambda sin proxy.

Antes de crear la API, configure el backend de Lambda mediante la creación de una función de Lambda en AWS Lambda, lo cual se describe a continuación.

Creación de una función de Lambda para la integración de Lambda no de proxy

nota

La creación de funciones de Lambda puede suponer cargos en su cuenta de AWS.

En este paso creará una función de Lambda del tipo "Hello, World!" para la integración personalizada de Lambda. En esta tutorial, la función se denomina GetStartedLambdaIntegration.

La implementación de esta función de Lambda GetStartedLambdaIntegration es la siguiente:

Node.js
'use strict'; var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; var times = ['morning', 'afternoon', 'evening', 'night', 'day']; console.log('Loading function'); export const handler = function(event, context, callback) { // Parse the input for the name, city, time and day property values let name = event.name === undefined ? 'you' : event.name; let city = event.city === undefined ? 'World' : event.city; let time = times.indexOf(event.time)<0 ? 'day' : event.time; let day = days.indexOf(event.day)<0 ? null : event.day; // Generate a greeting let greeting = 'Good ' + time + ', ' + name + ' of ' + city + '. '; if (day) greeting += 'Happy ' + day + '!'; // Log the greeting to CloudWatch console.log('Hello: ', greeting); // Return a greeting to the caller callback(null, { "greeting": greeting }); };
Python
import json days = { 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'} times = {'morning', 'afternoon', 'evening', 'night', 'day'} def lambda_handler(event, context): print(event) # parse the input for the name, city, time, and day property values try: if event['name']: name = event['name'] except KeyError: name = 'you' try: if event['city']: city = event['city'] except KeyError: city = 'World' try: if event['time'] in times: time = event['time'] else: time = 'day' except KeyError: time = 'day' try: if event['day'] in days: day = event['day'] else: day = '' except KeyError: day = '' # Generate a greeting greeting = 'Good ' + time + ', ' + name + ' of ' + \ city + '.' + ['', ' Happy ' + day + '!'][day != ''] # Log the greeting to CloudWatch print(greeting) # Return a greeting to the caller return {"greeting": greeting}

Para la integración de Lambda personalizada, API Gateway transmite la entrada a la función de Lambda del cliente como cuerpo de solicitud de integración. El objeto event de gestión de la función de Lambda es la entrada.

Nuestra función de Lambda es simple. Analiza el objeto de entrada event para las propiedades name, city, time y day. Entonces, devuelve un saludo, como un objeto JSON de {"message":greeting}, al intermediario. El mensaje se encuentra en el patrón "Good [morning|afternoon|day], [name|you] in [city|World]. Happy day!". Se supone que la entrada a la función de Lambda es del siguiente objeto JSON:

{ "city": "...", "time": "...", "day": "...", "name" : "..." }

Para obtener más información, consulte AWS Lambda Developer Guide.

Además, la función registra su ejecución en Amazon CloudWatch llamando a console.log(...). Esto es útil para rastrear llamadas cuando se depura la función. Para permitir que la función GetStartedLambdaIntegration registre la llamada, establezca un rol de IAM con las políticas apropiadas para la función de Lambda para crear los flujos de CloudWatch y agregar entradas de registro a los flujos. La consola de Lambda lo guía para crear los roles y políticas de IAM requeridos.

Si configura la API sin utilizar la consola de API Gateway (por ejemplo, si importa una API de un archivo de OpenAPI), tendrá que crear de forma explícita, si es necesario, y configurar un rol y una política de invocación para que API Gateway invoque las funciones de Lambda. Para obtener más información sobre cómo configurar los roles de ejecución e invocación de Lambda para una API de API Gateway, consulte Control del acceso a una API con permisos de IAM.

En comparación con GetStartedLambdaProxyIntegration, la función de Lambda para la integración de proxy de Lambda, la función de Lambda GetStartedLambdaIntegration para la integración personalizada de Lambda solo toma entradas del cuerpo de solicitud de integración de API de API Gateway. La función puede devolver una salida de cualquier objeto JSON, una cadena, un número, un booleano o incluso un blob binario. Por el contrario, la función de Lambda de la integración de proxy de Lambda puede tomar la entrada de cualquier dato solicitado, pero debe devolver una salida de un objeto JSON específico. La función GetStartedLambdaIntegration de la integración de Lambda personalizada puede tener los parámetros de solicitud de API como entrada, siempre que API Gateway asigne los parámetros de solicitud de API requeridos al cuerpo de solicitud de la integración antes de reenviar la solicitud del cliente al backend. Para que esto ocurra, el desarrollador de la API debe crear una plantilla de mapeo y debe configurarla en el método de API durante la creación de la API.

Ahora, cree la función de Lambda GetStartedLambdaIntegration.

Para crear la función de Lambda GetStartedLambdaIntegration para la integración personalizada de Lambda
  1. Abra la consola de AWS Lambda en https://console.aws.amazon.com/lambda/.

  2. Aplique alguna de las siguientes acciones:

    • Si aparece la página de bienvenida, elija Get Started Now (Empezar ahora) y, a continuación, elija Create function (Crear función).

    • Si aparece la página de lista Lambda > Functions (Lambda > Funciones), elija Create function (Crear función).

  3. Elija Author from scratch.

  4. En el panel Author from scratch (Crear desde cero), haga lo siguiente:

    1. En Name (Nombre), escriba GetStartedLambdaIntegration como nombre de la función de Lambda.

    2. En Tiempo de ejecución, elija el último tiempo de ejecución de Node.js o Python compatible.

    3. En Permissions (Permisos), expanda Change default execution role(Cambiar rol de ejecución predeterminado). En Rol de ejecución, elija Crear un nuevo rol desde las plantillas de políticas de AWS.

    4. En Role name (Nombre de la función), escriba un nombre para la función (por ejemplo, GetStartedLambdaIntegrationRole).

    5. En Policy templates (Plantillas de política), elija Simple microservice permissions (Permisos para microservicios sencillos).

    6. Elija Create function (Crear función).

  5. En el panel Configure function (Configurar función), en Function code (Código de función), configure los campos siguientes:

    1. Copie el código de la función de Lambda que aparece al comienzo de esta sección y péguelo en el editor del código en línea.

    2. Deje las opciones predeterminadas para todos los demás campos en esta sección.

    3. Elija Deploy (Implementar).

  6. Para probar la función recién creada, seleccione la pestaña Probar.

    1. En Nombre del evento, escriba HelloWorldTest.

    2. En JSON de evento, sustituya el código predeterminado por lo siguiente.

      { "name": "Jonny", "city": "Seattle", "time": "morning", "day": "Wednesday" }
    3. Elija Test (Probar) para invocar la función. Se muestra la sección Execution result: succeeded (Resultado de ejecución: realizada correctamente). Expanda Detalles y verá el siguiente resultado.

      { "greeting": "Good morning, Jonny of Seattle. Happy Wednesday!" }

      La salida también se escribe en CloudWatch Logs.

Como ejercicio secundario, puede utilizar la consola de IAM para ver el rol de IAM (GetStartedLambdaIntegrationRole) que fue creado como parte de la creación de la función de Lambda. Este rol de IAM posee dos políticas en línea asociadas. Una de ellas estipula los permisos más básicos para la ejecución de Lambda. Permite llamar a CreateLogGroup de CloudWatch para cualquier recurso de CloudWatch de su cuenta en la región donde se crea la función de Lambda. Esta política también permite crear flujos de CloudWatch y registrar eventos para la función de Lambda GetStartedLambdaIntegration.

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "logs:CreateLogGroup", "Resource": "arn:aws:logs:region:account-id:*" }, { "Effect": "Allow", "Action": [ "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": [ "arn:aws:logs:region:account-id:log-group:/aws/lambda/GetStartedLambdaIntegration:*" ] } ] }

El documento de la otra política se aplica para invocar otro servicio de AWS que no se utiliza en este ejemplo. Puede omitirla por ahora.

Asociada con el rol de IAM hay una entidad de confianza, que es lambda.amazonaws.com. Aquí se encuentra la relación de confianza:

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }

La combinación de esta relación de confianza y la política en línea hace que sea posible para la función de Lambda invocar una función console.log() para registrar los eventos en CloudWatch Logs.

Creación de una API con la integración de Lambda no de proxy

Con la función de Lambda (GetStartedLambdaIntegration) creada y probada, está listo para exponer la función a través de una API de API Gateway. Para fines ilustrativos, expondremos la función de Lambda con un método HTTP genérico. Utilizamos el cuerpo de solicitud, una variable de ruta de la URL, una cadena de consulta y un encabezado para recibir los datos de entrada requeridos del cliente. Activamos el validador de la solicitud de API Gateway para que la API asegure que todos los datos requeridos se definen y especifican de forma adecuada. Configuramos una plantilla de mapeo para que API Gateway transforme los datos de solicitud proporcionados por el cliente a un formato válido, según lo requiera la función de Lambda del backend.

Para crear una API con la integración de Lambda no de proxy
  1. Inicie sesión en la consola de API Gateway en https://console.aws.amazon.com/apigateway.

  2. Si es la primera vez que utiliza API Gateway, verá una página en la que aparecen las características del servicio. En REST API, elija Build (Compilación). Cuando aparezca el menú emergente Create Example API (Crear API de ejemplo), elija OK (Aceptar).

    Si esta no es la primera vez que utiliza API Gateway, elija Create API (Crear API). En REST API, elija Build (Compilación).

  3. En API name (Nombre de la API), escribaLambdaNonProxyAPI.

  4. (Opcional) En Description (Descripción), introduzca una descripción.

  5. Mantenga Tipo de punto de conexión de la API establecido en Regional.

  6. Seleccione Crear API.

Tras crear su API, cree un recurso /{city}. Este es un ejemplo de un recurso con una variable de ruta que toma una entrada del cliente. Más adelante, mapeará esta variable de ruta en la entrada de la función de Lambda mediante una plantilla de mapeo.

Para crear un recurso
  1. Elija Crear recurso.

  2. Mantenga Recurso proxy desactivado.

  3. Mantenga Ruta del recurso en /.

  4. En Nombre del recurso, escriba {city}.

  5. Mantenga desactivado CORS (uso compartido de recursos entre orígenes).

  6. Elija Crear recurso.

Tras crear su recurso /{city}, cree un método ANY. El verbo ANY de HTTP es un marcador para un método HTTP válido que un cliente envía en el tiempo de ejecución. Este ejemplo muestra que el método ANY se puede utilizar para la integración de Lambda personalizada y para la integración de proxy de Lambda.

Para crear un método ANY
  1. Seleccione el recurso /{city} y, a continuación, elija Crear método.

  2. En Tipo de método, seleccione CUALQUIERA.

  3. En Tipo de integración, seleccione Función de Lambda.

  4. Mantenga desactivada la Integración de proxy Lambda.

  5. En Función de Lambda, seleccione la Región de AWS en la que creó la función de Lambda y, a continuación, introduzca el nombre de la función.

  6. Elija Configuración de solicitud de método.

    Ahora, active un validador de la solicitud para una variable de ruta de la URL, un parámetro de cadena de consulta y un encabezado para garantizar que se hayan definido todos los datos necesarios. Para este ejemplo, se crea un parámetro de cadena de consulta time y un encabezado day.

  7. En Validador de solicitud, seleccione Validar parámetros de cadena de consulta y encabezados.

  8. Elija Parámetros de cadenas de consulta de URL y haga lo siguiente:

    1. Elija Add query string (Añadir cadena de consulta).

    2. En Nombre, escriba time.

    3. Active la opción Obligatorio.

    4. Mantenga Almacenamiento en caché desactivado.

  9. Elija Encabezados de solicitudes HTTP y haga lo siguiente:

    1. Elija Add header (Añadir encabezado).

    2. En Nombre, escriba day.

    3. Active la opción Obligatorio.

    4. Mantenga Almacenamiento en caché desactivado.

  10. Elija Crear método.

Tras activar un validador de solicitudes, se configura la solicitud de integración para el método ANYañadiendo una plantilla body-mapping para transformar la solicitud entrante en una carga JSON, tal y como exige la función de Lambda de backend.

Para configurar la solicitud de integración
  1. En la pestaña Solicitud de integración, en Configuración de solicitud de integración, elija Editar.

  2. En Acceso directo de cuerpo de la solicitud, elija Cuando no haya plantillas definidas (recomendado).

  3. Elija Plantillas de mapeo.

  4. Elija Add mapping template (Añadir plantilla de asignación).

  5. En Tipo de contenido, ingrese application/json.

  6. En Cuerpo de la plantilla, introduzca el siguiente código:

    #set($inputRoot = $input.path('$')) { "city": "$input.params('city')", "time": "$input.params('time')", "day": "$input.params('day')", "name": "$inputRoot.callerName" }
  7. Seleccione Guardar.

Prueba que invoca el método de API

La consola de API Gateway proporciona un servicio de pruebas para que pueda probar la invocación a la API antes de que se implemente. Puede utilizar la característica Prueba de la consola para probar la API mediante el envío de la siguiente solicitud:

POST /Seattle?time=morning day:Wednesday { "callerName": "John" }

En esta solicitud de prueba, configurará ANY en POST, establecerá {city} en Seattle, asignará Wednesday como el valor del encabezado day y asignará "John" como el valor callerName.

Para probar el método ANY
  1. Elija la pestaña Prueba. Puede que tenga que elegir el botón de flecha hacia la derecha para mostrar la pestaña.

  2. En Tipo de método, seleccione POST.

  3. En Ruta, debajo de ciudad, introduzca Seattle.

  4. En Cadenas de consulta, escriba time=morning.

  5. En Encabezados, escriba day:Wednesday.

  6. En Cuerpo de la solicitud, introduzca { "callerName": "John" }.

  7. Seleccione Test (Probar).

Compruebe que la carga de respuesta devuelta sea la siguiente:

{ "greeting": "Good morning, John of Seattle. Happy Wednesday!" }

También puede ver los registros para ver cómo API Gateway procesa la solicitud y la respuesta.

Execution log for request test-request Thu Aug 31 01:07:25 UTC 2017 : Starting execution for request: test-invoke-request Thu Aug 31 01:07:25 UTC 2017 : HTTP Method: POST, Resource Path: /Seattle Thu Aug 31 01:07:25 UTC 2017 : Method request path: {city=Seattle} Thu Aug 31 01:07:25 UTC 2017 : Method request query string: {time=morning} Thu Aug 31 01:07:25 UTC 2017 : Method request headers: {day=Wednesday} Thu Aug 31 01:07:25 UTC 2017 : Method request body before transformations: { "callerName": "John" } Thu Aug 31 01:07:25 UTC 2017 : Request validation succeeded for content type application/json Thu Aug 31 01:07:25 UTC 2017 : Endpoint request URI: https://lambda.us-west-2.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:GetStartedLambdaIntegration/invocations Thu Aug 31 01:07:25 UTC 2017 : Endpoint request headers: {x-amzn-lambda-integration-tag=test-request, Authorization=****************************************************************************************************************************************************************************************************************************************************************************************************************************************338c72, X-Amz-Date=20170831T010725Z, x-amzn-apigateway-api-id=beags1mnid, X-Amz-Source-Arn=arn:aws:execute-api:us-west-2:123456789012:beags1mnid/null/POST/{city}, Accept=application/json, User-Agent=AmazonAPIGateway_beags1mnid, X-Amz-Security-Token=FQoDYXdzELL//////////wEaDMHGzEdEOT/VvGhabiK3AzgKrJw+3zLqJZG4PhOq12K6W21+QotY2rrZyOzqhLoiuRg3CAYNQ2eqgL5D54+63ey9bIdtwHGoyBdq8ecWxJK/YUnT2Rau0L9HCG5p7FC05h3IvwlFfvcidQNXeYvsKJTLXI05/yEnY3ttIAnpNYLOezD9Es8rBfyruHfJfOqextKlsC8DymCcqlGkig8qLKcZ0hWJWVwiPJiFgL7laabXs++ZhCa4hdZo4iqlG729DE4gaV1mJVdoAagIUwLMo+y4NxFDu0r7I0/EO5nYcCrppGVVBYiGk7H4T6sXuhTkbNNqVmXtV3ch5bOlh7 [TRUNCATED] Thu Aug 31 01:07:25 UTC 2017 : Endpoint request body after transformations: { "city": "Seattle", "time": "morning", "day": "Wednesday", "name" : "John" } Thu Aug 31 01:07:25 UTC 2017 : Sending request to https://lambda.us-west-2.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:GetStartedLambdaIntegration/invocations Thu Aug 31 01:07:25 UTC 2017 : Received response. Integration latency: 328 ms Thu Aug 31 01:07:25 UTC 2017 : Endpoint response body before transformations: {"greeting":"Good morning, John of Seattle. Happy Wednesday!"} Thu Aug 31 01:07:25 UTC 2017 : Endpoint response headers: {x-amzn-Remapped-Content-Length=0, x-amzn-RequestId=c0475a28-8de8-11e7-8d3f-4183da788f0f, Connection=keep-alive, Content-Length=62, Date=Thu, 31 Aug 2017 01:07:25 GMT, X-Amzn-Trace-Id=root=1-59a7614d-373151b01b0713127e646635;sampled=0, Content-Type=application/json} Thu Aug 31 01:07:25 UTC 2017 : Method response body after transformations: {"greeting":"Good morning, John of Seattle. Happy Wednesday!"} Thu Aug 31 01:07:25 UTC 2017 : Method response headers: {X-Amzn-Trace-Id=sampled=0;root=1-59a7614d-373151b01b0713127e646635, Content-Type=application/json} Thu Aug 31 01:07:25 UTC 2017 : Successfully completed execution Thu Aug 31 01:07:25 UTC 2017 : Method completed with status: 200

Los registros muestran la solicitud entrante antes del mapeo y la solicitud de integración después del mapeo. Cuando una prueba falla, los registros son útiles para evaluar si la entrada original es correcta o si la plantilla de mapeo funciona correctamente.

Implementar la API

La invocación de prueba es una simulación que tiene limitaciones. Por ejemplo, elude cualquier mecanismo de autorización promulgado en la API. Para probar la ejecución de la API en tiempo real, primero debe implementar la API. Para implementar una API, usted crea una etapa para crear una snapshot de la API en ese momento. El nombre de etapa también define la ruta de base después del nombre de host predeterminado de la API. El recurso raíz de la API se agrega después del nombre de la etapa. Al modificar la API, debe volver a implementarla a una etapa nueva o existente antes de que los cambios surtan efecto.

Para implementar la API en una etapa
  1. Elija Deploy API (Implementar API).

  2. En Etapa, seleccione Nueva etapa.

  3. En Stage name (Nombre de etapa), escriba test.

    nota

    La entrada debe tener texto cifrado UTF-8 (es decir, no localizado).

  4. (Opcional) En Description (Descripción), introduzca una descripción.

  5. Elija Implementar.

En Detalles de la etapa, elija el icono de copia para copiar la URL de invocación de la API. El patrón general de esta URL base de la API es https://api-id.region.amazonaws.com/stageName. Por ejemplo, la URL base de la API (beags1mnid) creada en la región us-west-2 e implementada en la etapa test es https://beags1mnid.execute-api.us-west-2.amazonaws.com/test.

Pruebe la API en una etapa de implementación

Puede probar una API implementada de diferentes maneras. Para las solicitudes GET que solo utilizan variables de ruta de URL o parámetros de cadena de consulta, puede escribir la URL del recurso de la API en un explorador. Para otros métodos, debe utilizar utilidades de prueba de la API de REST más avanzadas, tales como POSTMAN o cURL.

Para probar la API mediante cURL
  1. Abra una ventana de la terminal en su equipo local conectado a Internet.

  2. Para probar POST /Seattle?time=evening:

    Copie el siguiente comando cURL y péguelo en la ventana de la terminal.

    curl -v -X POST \ 'https://beags1mnid.execute-api.us-west-2.amazonaws.com/test/Seattle?time=evening' \ -H 'content-type: application/json' \ -H 'day: Thursday' \ -H 'x-amz-docs-region: us-west-2' \ -d '{ "callerName": "John" }'

    Debería recibir una respuesta correcta con la siguiente carga:

    {"greeting":"Good evening, John of Seattle. Happy Thursday!"}

    Si cambia POST a PUT en esta solicitud de método, recibe la misma respuesta.

Eliminar recursos

Si ya no necesita las funciones de Lambda que ha creado para este tutorial, puede eliminarlas ahora. También puede eliminar los recursos de IAM asociados.

aviso

Si tiene previsto completar el resto de tutoriales de esta serie, no elimine el rol de ejecución de Lambda ni el rol de invocación de Lambda. Si elimina una función de Lambda que usan sus API, esas API dejarán de funcionar. La eliminación de una función de Lambda no se puede deshacer. Si desea utilizar la función de Lambda de nuevo, debe volver a crearla.

Si elimina un recurso IAM que usa una función de Lambda, esa función de Lambda dejará de funcionar y las API que dependen de esa función tampoco funcionarán. La eliminación de un recurso de IAM no se puede deshacer. Si desea utilizar el recurso de IAM de nuevo, debe volver a crearlo.

Para eliminar la función de Lambda
  1. Inicie sesión en la AWS Management Console y abra la consola de AWS Lambda en https://console.aws.amazon.com/lambda/.

  2. En la lista de funciones, elija GetStartedLambdaIntegration, Acciones y, a continuación, Eliminar función. Cuando se le pregunte, elija Delete (Eliminar) otra vez.

Para eliminar los recursos de IAM asociados
  1. Abra la consola de IAM en https://console.aws.amazon.com/iam/.

  2. En Details (Detalles), elija Roles (Roles).

  3. De entre la lista de roles, seleccione GetStartedLambdaIntegrationRole, elija Acciones del rol y, a continuación, Eliminar rol. Siga los pasos en la consola para eliminar el rol.