Tutorial: Crie uma API REST com uma integração de não proxy do Lambda - Amazon API Gateway

Tutorial: Crie uma API REST com uma integração de não proxy do Lambda

Nesta demonstração, usamos o console do API Gateway para criar uma API que permite a um cliente chamar funções do Lambda por meio da integração não proxy do Lambda (também conhecida como integração personalizada). Para obter mais informações sobre AWS Lambda e as funções do Lambda, consulte o Guia do desenvolvedor do AWS Lambda.

Para facilitar o aprendizado, escolhemos uma função do Lambda simples com configuração mínima da API para orientar você pelas etapas de criação de uma API do API Gateway com a integração personalizada do Lambda. Quando necessário, descrevemos parte da lógica. Para ver um exemplo mais detalhado da integração personalizada do Lambda, consulte Tutorial: Criar uma API REST de calculadora com duas integrações de serviços da AWS e uma integração sem proxy do Lambda.

Antes de criar a API, configure o backend do Lambda criando uma função do Lambda no AWS Lambda, conforme descrito a seguir.

Criar uma função do Lambda para integração não proxy do Lambda

nota

A criação de funções do Lambda pode resultar em cobranças na conta da AWS.

Nesta etapa, crie uma função do Lambda no estilo “Hello, World!” para a integração personalizada do Lambda. Durante esta demonstração, a função é chamada GetStartedLambdaIntegration.

A implementação dessa função do Lambda GetStartedLambdaIntegration é a seguinte:

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 a integração personalizada do Lambda o API Gateway transmite a entrada para a função do Lambda do cliente como o corpo da solicitação de integração. O objeto event do manipulador da função do Lambda é a entrada.

Nossa função do Lambda é simples. Ela analisa o objeto de entrada event para as propriedades name, city, timee day. Em seguida, ela retorna uma saudação, como um objeto JSON de {"message":greeting}, para o autor da chamada. A mensagem é no padrão "Good [morning|afternoon|day], [name|you] in [city|World]. Happy day!". Presume-se que a entrada para a função do Lambda seja um dos seguintes objetos JSON:

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

Para obter mais informações, consulte o Guia do desenvolvedor do AWS Lambda.

Além disso, a função registra sua execução no Amazon CloudWatch chamando console.log(...). Isso é útil para rastrear as chamadas ao depurar a função. Para permitir que a função GetStartedLambdaIntegration registre a chamada, defina uma função do IAM com as políticas apropriadas para que a função do Lambda crie os streams do CloudWatch e adicione entradas de log aos streams. O console do Lambda orienta você na criação das funções e políticas do IAM necessárias.

Se você configurar a API sem usar o console do API Gateway, tal como ao importar uma API de um arquivo do OpenAPI, é necessário criar explicitamente, se necessário, e configurar uma função e política de invocação para que o API Gateway invoque as funções do Lambda. Para obter mais informações sobre como configurar funções de invocação e execução do Lambda para uma API do API Gateway, consulte Controlar o acesso a uma API REST com permissões do IAM.

Em comparação com GetStartedLambdaProxyIntegration, a função do Lambda para a integração de proxy do Lambda, a função GetStartedLambdaIntegration do Lambda para a integração personalizada do Lambda recebe apenas a entrada do corpo da solicitação de integração da API do API Gateway. A função pode retornar uma saída de qualquer objeto JSON, uma string, um número, um Booleano ou até mesmo um blob binário. Em contrapartida, a função do Lambda para a integração de proxy do Lambda pode aceitar a entrada de quaisquer dados da solicitação, mas deve retornar uma saída de determinado objeto JSON. A função GetStartedLambdaIntegration para a integração personalizada do Lambda pode ter os parâmetros de solicitação de API como entrada, desde que o API Gateway mapeie os parâmetros de solicitação de API necessários para o corpo da solicitação de integração antes de encaminhar a solicitação do cliente ao backend. Para que isso aconteça, o desenvolvedor da API deve criar um modelo de mapeamento e configurá-lo no método de API ao criar a API.

Agora, crie a função do Lambda GetStartedLambdaIntegration.

Como criar a função do Lambda GetStartedLambdaIntegration para integração personalizada do Lambda
  1. Abra o console do AWS Lambda em https://console.aws.amazon.com/lambda/.

  2. Execute um destes procedimentos:

    • Se a página de boas-vindas for exibida, escolha Get Started Now (Começar a usar agora) e Create function (Criar função).

    • Se a página da lista Lambda > Functions (Lambda > Funções) for exibida, escolha Create function (Criar função).

  3. Escolha Author from scratch (Criar do zero).

  4. Na tela Author from scratch (Criar do zero), faça o seguinte:

    1. Em Name (Nome), insira GetStartedLambdaIntegration como o nome da função do Lambda.

    2. Em Tempo de execução, escolha o último runtime Node.js ou Python compatível.

    3. Em Permissions (Permissões), expanda Change default execution role (Alterar função de execução padrão). Na lista suspensa Perfil de execução, escolha Criar perfil com base em modelos de política da AWS.

    4. Para Role name (Nome da função), insira um nome para sua função (por exemplo, GetStartedLambdaIntegrationRole).

    5. Para Policy templates (Modelos de política), escolha Simple microservice permissions (Permissões de microsserviço simples).

    6. Escolha Create function (Criar função).

  5. No painel Configure function (Configurar função), em Function code (Código de função) faça o seguinte:

    1. Copie o código da função do Lambda listado no início desta seção e cole-o no editor de código em linha.

    2. Deixe as opções padrão para todos os outros campos nesta seção.

    3. Escolha Deploy (Implantar).

  6. Para testar a função recém-criada, escolha a guia Teste.

    1. Em Nome do evento, insira HelloWorldTest.

    2. Para JSON do evento, substitua o código padrão pelo seguinte.

      { "name": "Jonny", "city": "Seattle", "time": "morning", "day": "Wednesday" }
    3. Escolha Test (Testar) para invocar a função. A seção Execution result: succeeded (Resultada da execução: bem-sucedida) é exibida. Expanda Detalhes veja a saída a seguir.

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

      A saída também é gravada no CloudWatch Logs.

Como exercício extra, você pode usar o console do IAM para visualizar a função do IAM (GetStartedLambdaIntegrationRole) criada como parte da criação da função do Lambda. Há duas políticas em linha anexadas à esta função do IAM. Uma estipula as permissões mais básicas para execução do Lambda. Ela permite chamar o CreateLogGroup do CloudWatch para quaisquer recursos do CloudWatch de sua conta na região onde a função do Lambda for criada. Essa política também permite a criação de streams e eventos de registro em log do CloudWatch para a função do 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:*" ] } ] }

O outro documento de política se aplica à invocação de outro serviço da AWS que não é usado neste exemplo. Você pode ignorá-lo por enquanto.

Associada à função do IAM, há uma entidade confiável, que é lambda.amazonaws.com. Esta é a relação de confiança:

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

A combinação dessa relação de confiança e da política em linha possibilita que a função do Lambda invoque uma função console.log() para registro de eventos no CloudWatch Logs.

Criar uma API com integração não proxy do Lambda

Com a função do Lambda (GetStartedLambdaIntegration) criada e testada, você está pronto para expor a função por meio de uma API do API Gateway. Para fins de ilustração, a função do Lambda está exposta com um método HTTP genérico. Usamos o corpo de solicitação, uma variável do caminho URL, uma string de consulta e um cabeçalho para receber os dados de entrada necessários do cliente. Ativamos o validador de solicitações do API Gateway para a API a fim de garantir que todos os dados necessários sejam definidos e especificados apropriadamente. Configuramos um modelo para mapeamento para o API Gateway para transformar os dados de solicitação fornecidos pelo cliente no formato válido, conforme exigido pela função de backend do Lambda.

Como criar uma API com uma integração não proxy do Lambda
  1. Inicie uma sessão no console do API Gateway em https://console.aws.amazon.com/apigateway.

  2. Se esta for a primeira vez que você usa o API Gateway, você verá uma página com os recursos do serviço. Em REST API, escolha Build (Criar). Quando o pop-up Create Example API (Criar API de exemplo) for exibido, escolha OK.

    Se essa não for a primeira vez que você usa o API Gateway, escolha Create API (Criar API). Em REST API, escolha Build (Criar).

  3. Em API name (Nome da API), insira LambdaNonProxyAPI.

  4. (Opcional) Em Description (Descrição), insira uma descrição.

  5. Mantenha Tipo de endpoint da API definido como Regional.

  6. Selecione Criar API.

Depois de criar uma API, você criará um recurso /{city}. Este é um exemplo de recurso com uma variável de caminho que recebe uma entrada do cliente. Posteriormente, você vai associar essa variável de caminho à entrada da função do Lambda usando um modelo de mapeamento.

Para criar um recurso
  1. Selecione Criar recurso.

  2. Mantenha Recurso proxy desativado.

  3. Mantenha Caminho do recurso como /.

  4. Em Resource Name (Nome do recurso), insira {city}.

  5. Mantenha CORS (Compartilhamento de recursos de origem cruzada) desativado.

  6. Selecione Criar recurso.

Depois de criar um recurso /{city}, você criará um método ANY. O verbo HTTP ANY é um espaço reservado para um método HTTP válido que um cliente envia na ocasião da execução. Este exemplo mostra que o método ANY pode ser usado para integração personalizada do Lambda assim como para integração de proxy do Lambda.

Como criar um método ANY
  1. Selecione o recurso /{city} e, depois, Criar método.

  2. Em Tipo de método, selecione ANY.

  3. Em Tipo de integração, selecione Função do Lambda.

  4. Mantenha a opção Integração do proxy do Lambda desativada.

  5. Em Função do Lambda, selecione a Região da AWS onde você criou a função do Lambda e, depois, insira o nome da função.

  6. Escolha Configurações de solicitação de método.

    Agora, ative um validador de solicitações para uma variável de caminho de URL, um parâmetro de string de consulta e um cabeçalho a fim de garantir que todos os dados necessários sejam definidos. Neste exemplo, você vai criar um parâmetro de string de consulta time e um cabeçalho day.

  7. Em Validador de solicitação, selecione Validar parâmetros de string de consulta e cabeçalhos.

  8. Selecione Parâmetros de string de consulta de URL e faça o seguinte:

    1. Escolha Add query string (Adicionar string de consulta).

    2. Em Nome, digite time.

    3. Ative a opção Obrigatório.

    4. Mantenha Armazenamento em cache desativado.

  9. Selecione Cabeçalhos de solicitação HTTP e faça o seguinte:

    1. Escolha Add header (Adicionar cabeçalho).

    2. Em Nome, digite day.

    3. Ative a opção Obrigatório.

    4. Mantenha Armazenamento em cache desativado.

  10. Escolha Criar método.

Depois de ativar um validador de solicitações, você vai configurar a solicitação de integração do método ANY adicionando um modelo de mapeamento de corpo para transformar a solicitação recebida em uma carga útil do JSON, conforme exigido pela função do Lambda de back-end.

Como configurar a solicitação de integração
  1. Na guia Solicitação de integração em Configurações de solicitação de integração, selecione Editar.

  2. Em Passagem do corpo da solicitação, selecione Quando não há modelos definidos (recomendado).

  3. Selecione Modelos de mapeamento.

  4. Escolha Add mapping template (Adicionar modelo de mapeamento).

  5. Em Tipo de conteúdo, insira application/json.

  6. Em Corpo do modelo, insira o seguinte código:

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

Testar a chamada do método de API

O console do API Gateway fornece uma instalação de testes para que você teste a invocação à API antes que ela seja implantada. Você pode usar o recurso de teste do console para testar a API enviando a seguinte solicitação:

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

Nesta solicitação de teste, você definirá ANY como POST, definirá {city} como Seattle, atribuirá Wednesday como o valor de cabeçalho day e atribuirá "John" como o valor callerName.

Como testar o método ANY
  1. Selecione a guia Testar. Talvez seja necessário selecionar o botão de seta para a direita para mostrar a guia.

  2. Em Tipo de método, selecione POST.

  3. Em Caminho, em cidade, insira Seattle.

  4. Em Strings de consulta, digite time=morning.

  5. Em Cabeçalhos, insira day:Wednesday.

  6. Em Corpo da solicitação, insira { "callerName": "John" }.

  7. Escolha Test (Testar).

Verifique se a carga de resposta retornada é como se segue:

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

Também é possível visualizar os logs para examinar como o API Gateway processa a solicitação e a resposta.

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

Os logs mostram a solicitação recebida antes do mapeamento e a solicitação de integração após o mapeamento. Quando um teste falha, os logs são úteis para avaliar se a entrada original está correta ou se o modelo de mapeamento funciona corretamente.

Implantar a API

A invocação de teste é uma simulação e tem limitações. Por exemplo, ela ignora qualquer mecanismo de autorização promulgado na API. Para testar a execução da API em tempo real, você deve implantar a API primeiro. Para implantar uma API, você cria um estágio para criar um snapshot da API naquele momento. O nome do estágio também define o caminho base após o nome de host padrão da API. O recurso raiz da API é anexado após o nome do estágio. Quando você modifica a API, deve reimplantá-la em um estágio novo ou existente antes que as alterações entrem em vigor.

Para implantar a API em um estágio
  1. Escolha Implantar API.

  2. Em Estágio, selecione Novo estágio.

  3. Em Stage name (Nome do estágio), insira test.

    nota

    A entrada deve ser texto codificado UTF-8 (ou seja, não localizado).

  4. (Opcional) Em Description (Descrição), insira uma descrição.

  5. Escolha Implantar.

Em Detalhes do estágio, escolha o ícone de cópia para copiar o URL de invocação da API. O padrão geral do URL básico da API é https://api-id.region.amazonaws.com/stageName. Por exemplo, o URL básico da API (beags1mnid) criada na região us-west-2 e implantada no estágio test é https://beags1mnid.execute-api.us-west-2.amazonaws.com/test.

Testar a API em uma etapa de implantação

Há várias maneiras para testar uma API implantada. Para solicitações GET usando apenas variáveis de caminho do URL ou parâmetros de strings de consulta, é possível digitar o URL de recurso da API em um navegador. Para outros métodos, é necessário usar utilitários de teste de API REST mais avançados, como o POSTMAN ou o cURL.

Para testar a API usando cURL
  1. Abra uma janela de terminal em seu computador local conectado à Internet.

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

    Copie o seguinte comando cURL e cole-o na janela do 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" }'

    Você receberá uma resposta bem-sucedida com a seguinte carga:

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

    Se você alterar POST para PUT nesta solicitação de método, obterá a mesma resposta.

Limpar

Se você não precisar mais das funções do Lambda criadas para esta demonstração, poderá excluí-las agora. Você também pode excluir os recursos do IAM que o acompanham.

Atenção

Se você pretende completar as outras demonstrações desta série, não exclua a função de execução Lambda ou a função de invocação do Lambda. Se você excluir uma função do Lambda da qual as suas APIs dependem, essas APIs deixarão de funcionar. A exclusão de uma função do Lambda não pode ser desfeita. Se quiser usar a função do Lambda novamente, você deverá recriar essa função.

Se você excluir um recurso do IAM do qual depende uma função do Lambda, esta última deixará de funcionar, juntamente com as APIs que dependem dessa função. A exclusão de um recurso do IAM não pode ser desfeita. Se quiser usar o recurso do IAM novamente, você deverá recriá-lo.

Como excluir a função do Lambda
  1. Faça login no AWS Management Console e abra o console AWS Lambda em https://console.aws.amazon.com/lambda/.

  2. Na lista de funções, escolha GetStartedLambdaIntegration, Ações e Excluir função. Quando solicitado, escolha Delete (Excluir) novamente.

Como excluir os recursos do IAM associados
  1. Abra o console do IAM em https://console.aws.amazon.com/iam/.

  2. Em Details (Detalhes), escolha Roles (Funções).

  3. Na lista de funções, escolha GetStartedLambdaIntegrationRole, Ações da função e Excluir função. Siga as etapas no console para excluir o perfil.