Conceitos básicos da AWS

Crie uma aplicação Web sem servidor

com o AWS Lambda, Amazon API Gateway, AWS Amplify, Amazon DynamoDB e Amazon Cognito

Módulo 3: Serviço de backend sem servidor

Você usará o AWS Lambda e o Amazon DynamoDB para criar um processo de backend para processar solicitações de sua aplicação Web.

Visão geral

Neste módulo, você usará o AWS Lambda e o Amazon DynamoDB para criar um processo de backend para processar solicitações de sua aplicação Web. A aplicação do navegador que você implantou no primeiro módulo permite que os usuários solicitem o envio de um unicórnio para um local escolhido por eles. Para processar essas solicitações, o JavaScript executado no navegador precisará invocar um serviço executado na nuvem.

Visão geral da arquitetura

Visão geral da arquitetura

Você implementará uma função do Lambda que será invocada sempre que um usuário solicitar um unicórnio. A função vai selecionar um unicórnio da frota, gravar a solicitação em uma tabela do DynamoDB e, então, responder a aplicação de front-end com detalhes sobre o unicórnio que será despachado.

A função é invocada do navegador usando o Amazon API Gateway. Você implementará essa conexão no próximo módulo. Para este módulo, você apenas testará sua função em isolamento.

 Tempo para a conclusão

30 minutos

 Serviços usados

Implementação

  • Use o console do Amazon DynamoDB para criar uma nova tabela do DynamoDB. 

    1. No console do Amazon DynamoDB, escolha Criar tabela.
    2. Insira Ridescomo o Nome da tabela. Esse campo diferencia letras maiúsculas de minúsculas.
    3. Insira RideId para a Chave de partição e selecione String para o tipo de chave. Esse campo diferencia letras maiúsculas de minúsculas.
    4. Na seção Configurações da tabela, verifique se as Configurações padrão estão selecionadas e escolha Criar tabela
    5. Na página Tabelas, aguarde a conclusão da criação da tabela. Depois de concluído, o status será Ativo. Selecione o nome da sua tabela.
    6. Na guia Visão geral > seção Informações gerais da sua nova tabela, escolha Informações adicionais. Copie o ARN. Ele será usado na próxima seção.
  • Cada função do Lambda tem um perfil do IAM associado a ela. Essa função define com quais outros serviços da AWS a função tem permissão para interagir. Para os fins deste tutorial, você precisará criar um perfil do IAM que conceda permissão à função do Lambda para gravar logs no Amazon CloudWatch Logs e acesso para gravar itens na tabela do DynamoDB.

    1. No console do IAM, selecione Perfis no painel de navegação esquerdo e escolha Criar perfil.
    2. Na seção Tipo de entidade confiável, selecione Serviço da AWS. Em Caso de uso, selecione Lambda e, em seguida, escolha Avançar
      Observação: selecionar um tipo de perfil automaticamente cria uma política de confiança para o perfil que permite que os serviços da AWS assumam esse perfil em seu nome. Se estiver criando essa função a partir da CLI, do AWS CloudFormation ou de outro mecanismo, especifique diretamente uma política de confiança.
    3. Insira AWSLambdaBasicExecutionRole na caixa de texto do filtro e pressione Enter
    4. Marque a caixa de seleção ao lado do nome da política AWSLambdaBasicExecutionRole e escolha Avançar.
    5. Insira WildRydesLambda como Nome do perfil. Mantenha as configurações padrão para os outros parâmetros.
    6. Selecione Criar perfil.
    7. Na caixa de filtro na página Perfis, digite WildRydesLambda e selecione o nome do perfil que você acabou de criar.
    8. Na guia Permissões, escolha Adicionar permissões e, em seguida, escolha Criar política em linha.
    9. Na seção Selecionar um serviço, digite DynamoDB na barra de pesquisa e selecione DynamoDB quando ele aparecer.
    10. Escolha Selecionar ações.
    11. Na seção Ações permitidas, digite PutItem na barra de pesquisa e marque a caixa de seleção ao lado de PutItem quando ela aparecer.
    12. Na seção Recursos, com a opção Específico selecionada, selecione o link Adicionar ARN na seção tabela.
    13. Selecione a guia Texto. Cole o ARN da tabela que você criou no DynamoDB (Etapa 6 na seção anterior) e escolha Adicionar ARNs.
    14. Escolha Próxima.
    15. Insira DynamoDBWriteAccess para o nome da política e selecione Criar política.
  • O AWS Lambda executará seu código como resposta a eventos como uma solicitação HTTP. Nesta etapa, você criará a função básica que processará solicitações de API a partir do aplicativo web para despachar um unicórnio. No próximo módulo, você usará o Amazon API Gateway para criar uma API RESTful que vai expor um endpoint HTTP que pode ser invocado a partir dos navegadores dos usuários. Você se conectará a função do Lambda criada nesta etapa a essa API para criar um backend totalmente funcional para sua aplicação Web.

    Use o console do AWS Lambda para criar uma função do Lambda chamada RequestUnicorn, que processará as solicitações de API. Use a implementação de exemplo do requestUnicorn.js a seguir para o código da função. Basta copiar e colar daquele arquivo para o editor do console do AWS Lambda.

    Certifique-se de configurar sua função para usar o perfil do IAM WildRydesLambda criado na seção anterior.

    1. No console do AWS Lambda, escolha Criar função.
    2. Mantenha o cartão padrão Criar do zero selecionado.
    3. Insira RequestUnicorn no campo Nome da função.
    4. Selecione Node.js 16.x para o Runtime (as versões mais recentes do Node.js não funcionarão neste tutorial).
    5. Selecione Usar um perfil existente no menu suspenso Alterar perfil de execução padrão.
    6. Selecione WildRydesLambda na lista suspensa Perfil existente.
    7. Clique em Criar função.
    8. Role para baixo até a seção Origem do código e substitua o código existente no editor de código index.js pelo conteúdo de requestUnicorn.js. O bloco de código a seguir exibe o arquivo requestUnicorn.js. Copie e cole esse código na guia index.js do editor de código.
    const randomBytes = require('crypto').randomBytes;
    const AWS = require('aws-sdk');
    const ddb = new AWS.DynamoDB.DocumentClient();
    
    const fleet = [
        {
            Name: 'Angel',
            Color: 'White',
            Gender: 'Female',
        },
        {
            Name: 'Gil',
            Color: 'White',
            Gender: 'Male',
        },
        {
            Name: 'Rocinante',
            Color: 'Yellow',
            Gender: 'Female',
        },
    ];
    
    exports.handler = (event, context, callback) => {
        if (!event.requestContext.authorizer) {
          errorResponse('Authorization not configured', context.awsRequestId, callback);
          return;
        }
    
        const rideId = toUrlString(randomBytes(16));
        console.log('Received event (', rideId, '): ', event);
    
        // Because we're using a Cognito User Pools authorizer, all of the claims
        // included in the authentication token are provided in the request context.
        // This includes the username as well as other attributes.
        const username = event.requestContext.authorizer.claims['cognito:username'];
    
        // The body field of the event in a proxy integration is a raw string.
        // In order to extract meaningful values, we need to first parse this string
        // into an object. A more robust implementation might inspect the Content-Type
        // header first and use a different parsing strategy based on that value.
        const requestBody = JSON.parse(event.body);
    
        const pickupLocation = requestBody.PickupLocation;
    
        const unicorn = findUnicorn(pickupLocation);
    
        recordRide(rideId, username, unicorn).then(() => {
            // You can use the callback function to provide a return value from your Node.js
            // Lambda functions. The first parameter is used for failed invocations. The
            // second parameter specifies the result data of the invocation.
    
            // Because this Lambda function is called by an API Gateway proxy integration
            // the result object must use the following structure.
            callback(null, {
                statusCode: 201,
                body: JSON.stringify({
                    RideId: rideId,
                    Unicorn: unicorn,
                    Eta: '30 seconds',
                    Rider: username,
                }),
                headers: {
                    'Access-Control-Allow-Origin': '*',
                },
            });
        }).catch((err) => {
            console.error(err);
    
            // If there is an error during processing, catch it and return
            // from the Lambda function successfully. Specify a 500 HTTP status
            // code and provide an error message in the body. This will provide a
            // more meaningful error response to the end client.
            errorResponse(err.message, context.awsRequestId, callback)
        });
    };
    
    // This is where you would implement logic to find the optimal unicorn for
    // this ride (possibly invoking another Lambda function as a microservice.)
    // For simplicity, we'll just pick a unicorn at random.
    function findUnicorn(pickupLocation) {
        console.log('Finding unicorn for ', pickupLocation.Latitude, ', ', pickupLocation.Longitude);
        return fleet[Math.floor(Math.random() * fleet.length)];
    }
    
    function recordRide(rideId, username, unicorn) {
        return ddb.put({
            TableName: 'Rides',
            Item: {
                RideId: rideId,
                User: username,
                Unicorn: unicorn,
                RequestTime: new Date().toISOString(),
            },
        }).promise();
    }
    
    function toUrlString(buffer) {
        return buffer.toString('base64')
            .replace(/\+/g, '-')
            .replace(/\//g, '_')
            .replace(/=/g, '');
    }
    
    function errorResponse(errorMessage, awsRequestId, callback) {
      callback(null, {
        statusCode: 500,
        body: JSON.stringify({
          Error: errorMessage,
          Reference: awsRequestId,
        }),
        headers: {
          'Access-Control-Allow-Origin': '*',
        },
      });
    }

        9. Escolha Implantar.

  • Para este módulo, você testará a função criada usando o console do AWS Lambda. No próximo módulo, você adicionará uma API REST com o API Gateway para poder invocar sua função a partir da aplicação baseada em navegador implantado no primeiro módulo.

    1. Na função RequestUnicorn que você criou na seção anterior, escolha Testar na seção Origem do código e selecione Configurar evento de teste no menu suspenso.
    2. Mantenha a seleção padrão de Criar novo evento.
    3. Insira TestRequestEvent no campo Nome do evento.
    4. Copie e cole o seguinte evento de teste na seção JSON do evento:
    {
        "path": "/ride",
        "httpMethod": "POST",
        "headers": {
            "Accept": "*/*",
            "Authorization": "eyJraWQiOiJLTzRVMWZs",
            "content-type": "application/json; charset=UTF-8"
        },
        "queryStringParameters": null,
        "pathParameters": null,
        "requestContext": {
            "authorizer": {
                "claims": {
                    "cognito:username": "the_username"
                }
            }
        },
        "body": "{\"PickupLocation\":{\"Latitude\":47.6174755835663,\"Longitude\":-122.28837066650185}}"
    }

        5. Escolha Save (Salvar).

        6. Na seção Origem do código da sua função, escolha Testar e selecione TestRequestEvent no menu suspenso.

        7.  Na guia Testar, escolha Testar.

        8. Na mensagem Executando função: êxito exibida, expanda o menu suspenso Detalhes.

        9. Verifique se o resultado da função se parece com o seguinte:

    {
        "statusCode": 201,
        "body": "{\"RideId\":\"SvLnijIAtg6inAFUBRT+Fg==\",\"Unicorn\":{\"Name\":\"Rocinante\",\"Color\":\"Yellow\",\"Gender\":\"Female\"},\"Eta\":\"30 seconds\"}",
        "headers": {
            "Access-Control-Allow-Origin": "*"
        }
    }

Esta página foi útil para você?

Implantar uma API RESTful