
Hoje continuaremos nosso hands-on de uma arquitetura na AWS. Cada lambda irá receber um código em python para realizar suas tarefas, dessa forma, o conhecimento será direcionado a como acessar recursos da AWS e como fazer requisições a uma API pelo Python.
Este artigo tutorial é auxiliar ao vídeo gravado pelo trainee Guilherme Ferreira Rocha, que está no Youtube do TerraLAB. Veja aqui:
Esta é a parte 3 deste tutorial, então aconselhamos que, caso ainda não esteja acompanhando desde a primeira parte, volte para entender exatamente o que estamos arquitetando. O repositório HandsOn AWS-TerraLAB contém todo o código utilizado nos tutoriais.
Dando continuidade
- LAMBDA 1:
Iniciando com a codificação da primeira lambda, crie um arquivo chamado lambda1.py no diretório do seu serverless. As funções lambdas têm um padrão de definição da função e de seu retorno. Na definição precisamos receber um evento e um contexto, onde, o evento irá conter as informações vindas do trigger e o contexto fornece informações sobre o ambiente de execução da lambda. Para o retorno da função precisamos de um dicionário com um código de status http e um corpo de mensagem. Para nossa lambda definiremos o retorno de sucesso e o retorno de falha utilizando um try except. Esse código padrão deverá ficar assim para nossa arquitetura:
import json
def main(event, context):
try:
######
# código será inserido aqui
######
body = {
"message": f"",
"input": event,
}
response = {"statusCode": 200, "body": json.dumps(body)}
print(f"Lambda return = {body}")
except Exception as error:
body = {
"message": f"Error: {error}",
"input": event,
}
response = {"statusCode": 400, "body": json.dumps(body)}
print(f"Lambda return = {body}")
return response
A lambda 1 possui um gatilho http, o qual irá conter o nome do pokémon que queremos obter informações. Para recuperar esse nome, vamos acessar o dicionário event, na chave “queryStringParameters” e em sequência na chave “pokemon” como na linha a seguir:
pokemon = event["queryStringParameters"]["pokemon"]
Para realizarmos uma requisição à API PokéAPI utilizaremos a biblioteca requests do python. Adicione ela seus imports:
import requests
Continuando no código, faremos um request à API com o método GET para o nome do pokémon desejado, e depois converteremos a resposta em um dicionário python, desta forma:
response = requests.get(f"https://pokeapi.co/api/v2/pokemon/{pokemon}")
responseDict = json.loads(response.text)
O próximo passo seria enviar essa informação recebida da API para a fila MQ, mas antes, precisaremos recuperar as credenciais de acesso ao MQ que estão salvas no Secrets Manager. Para fazer isso precisaremos da biblioteca boto3, a qual é capaz de se conectar com os serviços da AWS. Adicione ela a seus imports:
import boto3
Seguindo os códigos de exemplo da própria AWS, iremos estabelecer uma conexão com o serviço, e tentar recuperar os valores do segredo. Caso essa operação seja bem sucedida, converteremos esses valores em um dicionário python, como no código a seguir:
client = boto3.client("secretsmanager")
secret_name = "tutorial/mq/users"
try:
secret_value = client.get_secret_value(SecretId=secret_name)
except Exception as e:
raise e
else:
secretDict = json.loads(secret_value["SecretString"])
username = secretDict["username"]
password = secretDict["password"]
Agora, com as credenciais em mãos, precisamos de mais duas informações para criar a conexão com a fila, o IP do broker e a porta que faremos a comunicação. Para isso, utilizaremos também a biblioteca boto3 para recuperar o IP, e a porta iremos utilizar a 61614 do protocolo STOMP de mensagens. O código ficará desta forma:
client = boto3.client("mq")
brokerInfo = client.describe_broker(BrokerId="fila-pokemon")
ipport = (brokerInfo["BrokerInstances"][0]["IpAddress"], "61614")
Finalmente, iremos enviar as informações para a fila. Aqui estaremos utilizando a biblioteca stomp.py para realizar a comunicação. Adicione ela a seus imports:
import stomp
Aqui, precisamos estabelecer uma conexão com a fila, informar qual protocolo de segurança será utilizado e por fim, enviar a mensagem em formato json, iremos também adicionar um tempo de espera pequeno para garantir o sucesso do envio. O protocolo de segurança iremos adquirir pelo pacote ssl nativo do python. Adicione ssl e time a seus imports.
import ssl
import time
O envio para fila deve ficar desta forma:
conn = stomp.Connection([ipport])
conn.set_ssl(for_hosts=[ipport], ssl_version=ssl.PROTOCOL_TLS)
conn.connect(username, password, wait=True)
conn.send(
body=json.dumps(responseDict),
destination="save-pokemon",
)
time.sleep(0.8)
Pronto, nossa lambda 1 está pronta, falta apenas mudarmos a mensagem de retorno para algo que faça sentido. O código completo deverá estar assim (com alguns prints adicionais informativos):
import json
import ssl
import time
import boto3
import requests
import stomp
def main(event, context):
try:
print("Getting query params")
pokemon = event["queryStringParameters"]["pokemon"]
print(f"Requesting {pokemon} to PokeAPI.")
response = requests.get(f"https://pokeapi.co/api/v2/pokemon/{pokemon}")
responseDict = json.loads(response.text)
print(f"Name = {responseDict['name']}, Types = {responseDict['types']}")
print("Connecting to Secrets Manager.")
client = boto3.client("secretsmanager")
secret_name = "tutorial/mq/users"
try:
print("Getting secrets values")
secret_value = client.get_secret_value(SecretId=secret_name)
except Exception as e:
raise e
else:
secretDict = json.loads(secret_value["SecretString"])
username = secretDict["username"]
password = secretDict["password"]
print("Connecting to MQ.")
client = boto3.client("mq")
print("Getting broker IP")
brokerInfo = client.describe_broker(BrokerId="fila-pokemon")
ipport = (brokerInfo["BrokerInstances"][0]["IpAddress"], "61614")
print(f"ip/port = {ipport}")
conn = stomp.Connection([ipport])
conn.set_ssl(for_hosts=[ipport], ssl_version=ssl.PROTOCOL_TLS)
conn.connect(username, password, wait=True)
conn.send(
body=json.dumps(responseDict),
destination="save-pokemon",
)
time.sleep(0.8)
print("Function is over.")
body = {
"message": f"Pokémon {responseDict['name']} sent to queue",
"input": event,
}
response = {"statusCode": 200, "body": json.dumps(body)}
print(f"Lambda return = {body}")
except Exception as error:
body = {
"message": f"Error: {error}",
"input": event,
}
response = {"statusCode": 400, "body": json.dumps(body)}
print(f"Lambda return = {body}")
return response
Antes de realizarmos o deploy do nosso serverless, precisamos configurar os requisitos de bibliotecas do python que as lambdas terão necessidade de acessar. Crie o arquivo “requirements.txt” no diretório do seu serverless e escreva em cada linha dele as bibliotecas que precisamos, como a seguir:
boto3
requests
stomp.py
Agora, abra o terminal (no diretório do serverless) e digite o seguinte comando:
serverless plugin install -n serverless-python-requirements
Com esse comando, o campo de plugin é adicionado ao arquivo “serverless.yml“ e para finalizar nossa configuração, adicionaremos ainda ao final do arquivo “serverless.yml“ o nome do executável python do seu computador. Por exemplo, se para compilar um código em python você utiliza “python3 seuprograma.py”, você deverá informa “python3” na configuração seguinte:
custom:
pythonRequirements:
pythonBin: python3
Feito tudo isso, agora é só realizar o deploy, novamente abra o terminal no diretório do seu serverless e rode o comando:
serverless deploy
Se tudo correr como o esperado, aparecerá um link após a execução da lambda com o qual você pode testar se ela está funcionando como deveria. Basta copiar o link para seu navegador de preferência e adicionar ?pokemon=<pokemon-escolhido> ao fim da url e clicar enter. Um exemplo, se você escolheu o pokémon pikachu, vai ficar ?pokemon=pikachu e irá aparecer os prints informativos correspondentes ao pokémon pikachu.
Conclusão
Aprendemos nesse tutorial a configurar uma função lambda para solicitar informações a uma API por meio do python e suas bibliotecas. Além disso, vimos como decodificar a informação recebida para que ela possa ser utilizada. Por fim, aprendemos como colocar essa informação na fila, bem como conectar com ela.
No próximo tutorial, finalizaremos a arquitetura construída.
Se você se interessou pelo assunto, temos mais sobre o tema em nosso blog.
Você sabia que este artigo foi escrito por um trainee do TerraLAB? Você sabe como a escassez de profissionais qualificados impacta as empresas de Tecnologia da Informação? Clique aqui para conhecer os desafios desta indústria e como uma parceria com o TerraLAB pode ajudar você e a sua empresa. O TerraLAB é um celeiro de talentos que prepara estudantes para o mercado de trabalho, oferecendo vivências em projetos reais e experiência nos mais modernos processos e ferramentas de desenvolvimento de software. Siga-nos nas redes sociais para saber mais!
Este artigo foi escrito por Guilherme Ferreira Rocha, revisado por Prof. Rodrigo Silva.