Como disponibilizar um serviço web sem “pagar” servidor

Bruno Proença
SynchroTEC
Published in
7 min readDec 2, 2016

Neste artigo, vamos falar um pouco sobre como disponibilizar um micro-serviço web sem pagar por uma instância rodando no server-side. A mágica para não pagar nada, ou apenas pagar pelo código executado, será feito usando as tecnologias Lambda e API Gateway da AWS.

Esse conceito tem sido chamado no mercado como “serverless”, pois você não precisa se preocupar com um servidor/instância. Apesar de usarmos nesse artigo um serviço da AWS, temos opções equivalentes em outros vendors como Microsoft Azure e Google Cloud Platform.

Essa é uma opção muito interessante quando não queremos deixar uma instância no ar 24 x 7. Pode ser que nosso serviço seja acessado apenas algumas vezes no mês. Também não queremos nos preocupar com a robustez desse serviço em eventuais picos de processamento.

Vamos ver uma alternativa simples e barata para expor um micro-serviço pagando apenas quando nosso código for executado, ao invés de partir para uma arquitetura tradicional: Instância + LoadBalance + AutoScalling + etc.

Para essa demonstração, nosso micro-serviço vai realizar uma operação bem simples: ele vai receber dois números como parâmetro (“x” e “y”), realizar a soma desses valores no server-side, e retornar o resultado. Vamos expor essa complexa (rsrs) inteligência numa API (invoke URL). E por último criar um cliente para consumir esse recurso.

Vamos construir isso passo-a-passo em 3 etapas:

Etapa 1 — Lambda (server-side)

Primeiro vamos criar nossa lógica de negócio (server-side) que realiza a soma de dois valores. Para isso vamos criar uma função Lambda (obs.: o serviço Lambda ainda não está disponível em todas as regiões).

No menu AWS clique em Lambda:

Na página principal do AWS Lambda, clique no botão Create a Lambda function. Você pode escolhe criar sua função Lambda a partir de vários blueprints.

Para esse exemplo, vamos usar a opção Blank Function.

O próximo passo é escolher a Trigger. Por enquanto vamos deixar essa opção em branco, uma vez que isso será demonstrado na Etapa 2 desse post.

Agora vem a parte interessante de criação da função Lambda, é aqui no passo Configure function que vamos incluir nosso código. O serviço AWS Lambda suporta (até a data desse post), os seguintes Runtimes:

  • Java 8
  • Node.js 0.10
  • Node.js 4.3
  • Python 2.7

Em nosso exemplo, vamos usar o runtime Node.js 4.3 com o código abaixo:

exports.handler = function(event, context) {
var valorX = 0;
var valorY = 0;

console.log("request: " + JSON.stringify(event));

if (event.queryStringParameters !== null) {
if (event.queryStringParameters.x !== null
&& event.queryStringParameters.y !== null) {

valorX = parseInt(event.queryStringParameters.x);
valorY = parseInt(event.queryStringParameters.y);

console.log("Received x: " + valorX);
console.log("Received y: " + valorY);
}
}

var responseBody = {
valorCalculado: valorX + valorY
};
var response = {
headers: {
"Access-Control-Allow-Origin" : "*"
},
body: JSON.stringify(responseBody)
};

console.log("response: " + JSON.stringify(response))
context.succeed(response);
};

Esse código soma os valores de X e Y, recebidos como parâmetro, e retorna o resultado no response body. Também adicionamos um parâmetro no response header para permitir CORS.

Nas demais opções, vamos configurar da seguinte forma:

Clique Next, revise todo conteúdo e depois crie sua função Lambda.

Depois de criada, existe uma opção muito interessante para testar sua função Lambda diretamente pelo AWS Console.

Clique no botão Test, um popup vai abrir para você informar os parâmetros que serão passados para sua função Lambda. Veja que você pode escolher algum dos templates para montar seu input. Nosso teste vai passar os parâmetro X e Y:

Clique Save and Test. O teste vai disparar uma execução da função Lambda e gerar o resultado esperado:

Você pode monitorar as execuções de funções Lambdas na opção Monitoring, e também consultar logs pela opção View logs in CloudWatch.

Etapa 2 — API Gateway (invoke URL)

Agora que nosso código Lambda está funcionando, vamos expor isso como um serviço-web. Para tal usaremos a tecnologia AWS API Gateway.

Volte ao menu AWS e clique na opção API Gateway. Depois Clique no botão Create API e informe um nome.

Na opção seguinte, clique no botão Action e em seguida Create Resource. Preencha conforme abaixo:

No exemplo acima, chamamos o nosso resource, e respectivo path, de somar. Não se esqueça de marcar a opção CORS, caso contrário teremos problemas para acessar nosso serviço (client-side) pelo JavaScript.

Agora vamos configurar a API Gateway para atuar como um proxy integration para a função Lambda. Ela será o gatilho para a execução da lógica de negócio do Lambda.

O última passo da etapa 2 é realizar o deploy da nossa API. Clique novamente no menu Actions e depois Deploy API. Informe ou crie um novo stage (ambiente) para seu deploy.

Pronto sua API está no ar. Na opção de menu Stages você poderá ver a URL da sua API. Veja que o nome do stage está no path da URL. Experimente chamar seu serviço direto pelo navegador. Não se esqueça de concatenar na URL o nome do resource (em nosso exemplo chamado: /somar)

Caso você enfrente algum problema para chamar seu micro-serviço, experimente testar diretamente pelo AWS Console conforme abaixo e verificar os Logs de execução:

Etapa 3 — Java Script (client-side)

Para finalizar, vamos construir um cliente que vai consumir o nosso serviço. Em nosso exemplo vamos criar uma tela simples onde o usuário pode informar 2 valores, clicar no botão e ver o resultado da soma.

A função JavaScript calculate() é a responsável por fazer uma requisição ajax para nosso serviço e mostrar o resultado.

<!DOCTYPE html>
<html>
<head>
<title>Serverless</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<p>
Valor X: <input id="x" type="text" value="2" name="valor"><br>
Valor Y: <input id="y" type="text" value="3" name="valor">
</p>
<p>
<input type="button" onclick="calculate()" value="Somar">
</p>
<p id="result"></p><script>function calculate() {
var params = {
x:document.getElementById("x").value,
y:document.getElementById("y").value
};
$.ajax({
type: "GET",
url: "https://<url>.amazonaws.com/dev/somar",
dataType: "json",
data: params,
success: function (data) {
document.getElementById("result")
.innerHTML = data.valorCalculado;
},
error: function () {
alert("deu erro")
}
});
}
</script></body>
</html>

Resultado esperado:

Pontos adicionais

Nosso exemplo usou um cenário extremamente simples, sem se preocupar com questões de design e segurança. Vou citar alguns recursos adicionais que você pode explorar.

Nossa função Lambda faz uma tarefa bem simples. No entanto você poderia escrever um código mais sofisticado e acessar outros serviços, como por exemplo S3 ou DynamoDB. Lembra quando criamos o Lambda que tinha um campo Role Name? Então, podemos usar esse recurso para delimitar que tipo de acesso nossa função Lambda pode ter.

No serviço API Gateway temos outros recursos bem interessantes:

  • Possibilidade de vincular nossa API Gateway à uma chave (API Key). Dessa forma seu serviço só pode ser acionado se a chave for passada no header da requisição.
$.ajax({
type: "GET",
url: "https://<URL>",
dataType: "json",
data: params,
headers: {
"x-api-key": "<my-key>"
},
...
  • Outra opção é vincular o API Gateway a um Usage Plan. Dessa forma é possível estabelecer alguns limites conforme abaixo:

Conclusão

Nesse artigo foi possível ver uma forma simples de construir um micro-serviço usando função Lambda, expor um end-point usando o API Gateway e consumindo esse serviço através de uma tela HTML + Javascript simples.

Mesmo depois dezenas de testes num final de semana, veja como ficou os gastos para deixar tudo isso no ar:

Espero que tenham gostado. Um brande abraço!!!

--

--