Wednesday, January 1, 2020

AWS: API Gateway e Lambda: parte 1

AWS Lambda e API Gateway


API Gateway é um serviço da AWS para criar, publicar, manter e monitorar de maneira muito simples APIs REST ou Web Socket que servem como porta de entrada para serviços que operam no back-end como acesso ao banco de dados, processamento de regras de negócios e diversas outras funcionalidades.


APIs REST são baseadas no protocolo HTTP e implementam os métodos padrões deste protocolo tais como GET, PUT, POST, DELETE e PATCH.

Neste artigo fazemos uma introdução a API Gateway com REST endpoints chamando outro serviço AWS no back-end, neste caso AWS Lambda.

AWS Lambda


Lambda é outro serviço da AWS que permite executar um código baseado em algum evento. O diferencial do Lambda é que ele é sevrerless, ou seja, você apenas cria sua lógica e a AWS cuida de toda infraestrutura necessária como escalonamento, memória, processamento, etc. Lambdas são como funções que rodam na nuvem, cujo código pode ser disparado sob diversas formas.

API Gateway + Lambda

Um caso de uso muito comum é integrar os serviços API Gateway e Lambdas, de modo que a chamada ao primeiro dispare a execução da lógica no segundo. Como exemplo dessa integração:
  1. Criamos uma função Lambda que cria um JSON e o retorna (parte 1)
  2. Um REST endpoint via API Gateway que chama a função e retorna seu resultado (parte 2)
Para executar o exemplo é necessário que você tenha pelo menos uma conta gratuita na AWS e instalar a ferramenta AWS CLI, que permite gerenciar os serviços da AWS por linha de comando.

Criando o Lambda

Utilizando sua IDE de preferencia (neste exemplo uso o INteliJ), crie um projeto MAVEN. O arquivo pom.xml contém as dependencias para se trabalhar com o Lambda e manipulação de JSON com a API gson google:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.finalexception</groupId>
    <artifactId>LambdaApiGatewayP01</artifactId>
    <version>1.0</version>
    <name>lambda-api</name>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.6</version>
        </dependency>
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-lambda-java-core</artifactId>
            <version>1.1.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <createDependencyReducedPom>false</createDependencyReducedPom>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

O plugin maven-shade permite compactar todas as dependencias junto com o jar final. Isso será necessário ao subir o arquivo compactado do projeto para executá-lo na nuvem.
Crie um pacote chamado service.lambda e crie classe Function01 cujo código é o que segue:

package service.lambda;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
import com.google.gson.JsonObject;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

public class Function01 implements RequestStreamHandler{

    @Override
    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException
    {
        //API para manipulacao de JSONs
        JsonObject responseJson = new JsonObject();
        JsonObject responseBody = new JsonObject();
        JsonObject headerJson = new JsonObject();

        //propriedade mensagem na resposta
        responseBody.addProperty("message", "it's everything OK here!");

        // um header aleatório na resposta para API Gateway
        headerJson.addProperty("x-custom-header", "my custom header value");

        // Http status code 200 OK
        responseJson.addProperty("statusCode", 200);
        responseJson.add("headers", headerJson);
        responseJson.addProperty("body", responseBody.toString());

        // serializa o JSON para um OutputStream
        OutputStreamWriter writer = new OutputStreamWriter(outputStream, "UTF-8");
        writer.write(responseJson.toString());
        writer.close();
    }
}


A partir da raiz do seu projeto, rode o comando mvn clean package para empacotar o projeto, gerando o arquivo LambdaApiGatewayP01-1.0.jar

Fazendo o deploy do arquivo na AWS

Agora vamos enviar o arquivo do projeto para o serviço AWS Lambda. A partir da raiz do seu projeto, execute o seguinte comando:

aws lambda create-function --function-name funcao01 \
    --zip-file fileb://target/LambdaApiGatewayP01-1.0.jar \
    --handler service.lambda.Function01::handleRequest \
    --runtime java8 \
    --role arn:aws:iam::12121212121:role/developer

O valor do parâmetro --role deve ser qualquer role na sua conta AWS que tenha autorização para criar Lambdas. Quando você cria uma conta, no mínimo deve ter a role administrador, que possui todas as permissões.

Após criar a função, é retornado um JSON contendo várias propriedades da mesma. Observe e copie o valor da propriedade functionArn, representa o endereço dessa função específica no ambiente AWS. Ao invocar essa função, utilizaremos o valor desse functionArn.

Agora que você publicou a função, faça um teste invocando-a. Substitua o valor de functionArn perlo valor gerado na sua conta:

 aws lambda invoke --function-name arn:aws:lambda:us-east-1:205303771310:function:funcao01 \
      --invocation-type RequestResponse /tmp/outfile.txt

O parâmetro /tmp/outfile contém a resposta gerada pela função no formato JSON. Você pode checá-lo abrindo o arquivo:


Na segunda parte intergamos essa função com um endpoint REST via API Gateway. Dessa forma, requisições HTTP no endpoint farão a função disparar.

Referências:
https://aws.amazon.com/lambda/
https://aws.amazon.com/api-gateway/

"Quanto a vocês, não fiquem procurando o que vão de comer e o qque vão beber. Não fiquem inquietos. Porque são os pagãos deste mundo que procuram tudo isso. O Pai bem sabe que vocês têm necessidade dessas coisas. Portanto, busquem o Reino dele, e Deus dará a vocês essas coisas em acréscimo. Não tenha medo, pequeno rebanho, porque o Pai de vocês tem prazer em dar-lhes o Reino"

Lucas 12:29-31


       

4 comments:

  1. para criar esse projeto no eclipse usaria qual configuração para startar o projeto

    ReplyDelete
    Replies
    1. projeto maven normal, pra qualquer IDE

      Delete
    2. na verdade seria o Archetype
      por que no eclipse pede para selecionar um e no vídeo não mostra qual.

      Delete
  2. GroupId: org.apache.maven.archetypes
    ArtifactId: maven-archetype-quickstart
    Version: 1.4
    Repository URL: https://repo1.maven.org/maven2

    ReplyDelete