https://a.storyblok.com/f/270183/105943/367a8c75aa/aws_sms_1200x675.jpg

Envie mensagens com o Nexmo usando Golang e o AWS Lambda

Publicado em May 21, 2021

Tempo de leitura: 6 minutos

Recentemente, assisti a um tutorial do Tom Morris no blog da Nexmo intitulado Enviando SMS a partir do Python com o Google Cloud Functions, e achei que era um exemplo interessante de uso de mensagens SMS, mesmo que Python e o Google Cloud Functions não sejam minhas áreas habituais.

Depois de ler o blog, achei que seria interessante expandi-lo para usar o AWS Lambda como provedor de funções e mudar a linguagem para Golang, algo pelo qual sou muito apaixonado.

Neste tutorial, vamos criar uma API usando o AWS Lambda e o AWS API Gateway que envia uma mensagem SMS com a API de mensagens da Nexmo, mas utilizando a linguagem de programação Go.

Os requisitos

Há alguns requisitos que devem ser atendidos antes de seguir com este tutorial:

  • É preciso ter o Go instalado e estar pelo menos um pouco familiarizado com a linguagem.

  • Você precisa ter um account de desenvolvedor da Nexmo.

  • Você precisa ter um Account na Amazon Web Services.

Como o Go é uma linguagem compilada, precisamos poder desenvolver e compilar localmente. Nossas compilações serão enviadas para a AWS, daí a necessidade de um Account na AWS. Essas Applications utilizarão a Messages API da Nexmo.

Criação de uma função de mensagens com Go e o SDK do AWS Lambda

No que diz respeito ao desenvolvimento do aplicativo em Go, não há muita coisa acontecendo. Em termos do fluxo de eventos, eles ficarão mais ou menos assim:

  1. O usuário fará uma solicitação à função.

  2. A função enviará uma solicitação HTTP para a Messages API do Nexmo.

  3. A função retornará o ID do erro ou da mensagem fornecido pela API.

Embora a lógica principal gire em torno de uma solicitação HTTP, será necessário fazer algumas configurações relacionadas ao modelo de dados da solicitação e da resposta.

Dentro do $GOPATH, crie um novo projeto com um arquivo main.go que contenha o seguinte:

package main

var NEXMO_API_KEY string = "API_KEY_HERE"
var NEXMO_API_SECRET string = "API_SECRET_HERE"

func main() {}

Tanto a chave da API quanto o segredo da API podem ser obtidos no portal do desenvolvedor da Nexmo.

Como este será um projeto do AWS Lambda, é necessário instalar o SDK do Go para o Lambda. Na linha de comando, execute o seguinte:

go get github.com/aws/aws-lambda-go/lambda

Com o SDK instalado por meio do gerenciador de pacotes Go, ele pode ser utilizado no projeto. Para utilizá-lo no projeto, podemos fazer as seguintes alterações:

package main

import "github.com/aws/aws-lambda-go/lambda"

var NEXMO_API_KEY string = "API_KEY_HERE"
var NEXMO_API_SECRET string = "API_SECRET_HERE"

func Handler() {}

func main() {
    lambda.Start(Handler)
}

Como você provavelmente já deve imaginar, toda a nossa lógica de mensagens estará na Handler função, já que é ela que será executada quando o cliente fizer uma solicitação Lambda.

Antes de entrarmos na lógica, precisamos definir alguns modelos de dados para as diversas solicitações e respostas. O Go exige que definamos explicitamente nossos modelos de dados por meio de struct variáveis, para que o JSON possa ser marshalado corretamente entre as solicitações.

Adicione o seguinte ao arquivo arquivo main.go :

type NexmoMessageContent struct {
	Type string `json:"type"`
	Text string `json:"text"`
}

type NexmoMessage struct {
	Content NexmoMessageContent `json:"content"`
}

type NexmoMessageService struct {
	Type   string `json:"type"`
	Number string `json:"number"`
}

type NexmoMessagesRequest struct {
	From    NexmoMessageService `json:"from"`
	To      NexmoMessageService `json:"to"`
	Message NexmoMessage        `json:"message"`
}

type NexmoMessagesResponse struct {
	Id string `json:"message_uuid"`
}

Se você já utilizou a Messages API, deve estar familiarizado com o JSON que deve ser enviado em cada solicitação à API. As estruturas de dados acima representam os dados que serão enviados. Com as anotações JSON em vigor, o JSON ficaria mais ou menos assim:

{
    "from": { "type": "sms", "number": "SENDER_NUMBER_HERE" },
    "to": { "type": "sms", "number": "RECIPIENT_NUMBER_HERE" },
    "message": {
        "content": {
            "type": "text",
            "text": "Hello World"
        }
    }
}

Ao enviar uma solicitação à Messages API, será retornada uma resposta com um UUID caso a solicitação tenha sido bem-sucedida. Criamos uma NexmoMessagesResponse estrutura que armazena esses dados e pretendemos enviá-la de volta ao cliente.

A única coisa que falta agora é a solicitação que o cliente fará à função Lambda. Se nosso exemplo estiver tentando imitar o exemplo do Google Cloud Functions, esperamos receber o número de telefone do destinatário e a plataforma móvel que ele está usando.

Com essas informações em mente, podemos criar uma estrutura de dados semelhante à seguinte:

type LambdaRequest struct {
	Platform  string `json:"platform"`
	Recipient string `json:"recipient"`
}

Com todos os modelos de dados criados, podemos concentrar o restante de nossos esforços na realização da solicitação de mensagem.

Fazer solicitações HTTP em Go não é um processo difícil. Expliquei algumas dessas abordagens em detalhes em um tutorial anterior que escrevi, intitulado “Utilizando Endpoints de API RESTful em um Aplicativo Golang”, embora minha escolha pessoal seja usar uma estrutura Go http.Client . Neste exemplo específico, precisaremos fazer uma solicitação POST, conforme descrito na documentação da Nexmo.

Vamos começar criando uma SendMessage função que, basicamente, criará uma solicitação semelhante à dos diversos exemplos do cURL da Nexmo:

func SendMessage(body map[string]string) (NexmoMessagesResponse, error) {
	nexmoMessagesRequest := &NexmoMessagesRequest{
		From: NexmoMessageService{
			Type:   "sms",
			Number: body["from"],
		},
		To: NexmoMessageService{
			Type:   "sms",
			Number: body["to"],
		},
		Message: NexmoMessage{
			Content: NexmoMessageContent{
				Type: "text",
				Text: body["message"],
			},
		},
	}
	bodyData, _ := json.Marshal(nexmoMessagesRequest)
	request, _ := http.NewRequest("POST", "https://api.nexmo.com/v0.1/messages", bytes.NewBuffer(bodyData))
	request.Header.Set("Content-Type", "application/json")
	request.Header.Set("Accept", "application/json")
	request.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(NEXMO_API_KEY+":"+NEXMO_API_SECRET)))
	client := &http.Client{}
	response, err := client.Do(request)
	if err != nil {
		return NexmoMessagesResponse{}, err
	} else {
		data, _ := ioutil.ReadAll(response.Body)
		var result NexmoMessagesResponse
		json.Unmarshal(data, &result)
		return result, nil
	}
}

A função acima receberá um map[string]string e retornará um NexmoMessagesResponse ou um erro. A primeira parte da função obtém dados do mapa e constrói um objeto que será convertido para JSON. Na hora de construir a solicitação HTTP, o objeto é usado como corpo e vários cabeçalhos são definidos, sendo que um deles é um cabeçalho de autorização.

Com o Nexmo, é possível usar um JSON Web Token (JWT) ou a chave de API e o segredo de API. Neste exemplo, serão utilizados a chave de API e o segredo de API.

É na SendMessage função é responsável pela maior parte do trabalho realizado.

Como estamos usando o SDK do AWS Lambda para Go e temos uma Handler função, o próximo passo é definir o que consta na Handler função. Deve ficar mais ou menos assim:

func Handler(request LambdaRequest) (NexmoMessagesResponse, error) {
	return SendMessage(
		map[string]string{
			"from":    "15404161937",
			"to":      request.Recipient,
			"message": request.Platform,
		},
	)
}

Lembre-se de que o cliente que acessa nossa API deve fornecer as informações sobre a plataforma e o destinatário. Lembre-se de que ele precisa definir qual plataforma móvel está usando e o número de telefone para o qual a mensagem SMS deve ser enviada.

Por incrível que pareça, a função AWS Lambda está pronta. Quando acionada com as informações corretas do destinatário e da plataforma, a mensagem SMS será enviada e o ID da mensagem será retornado.

Em seguida, precisamos integrar a função ao AWS Lambda e torná-la acessível por meio de solicitações HTTP padrão, como é comum em uma API.

Configurando o AWS Lambda e o AWS API Gateway como uma API da Web escalável

Antes mesmo de acessarmos o portal da AWS, provavelmente devemos compilar nosso projeto em Go. Na linha de comando, estando no diretório do projeto, execute o seguinte:

GOOS=linux go build

A AWS exige que nossas aplicações sejam compatíveis com o Linux. Para nossa sorte, o Go já vem com todas as cadeias de ferramentas necessárias para a compilação cruzada. Para mais informações sobre compilação cruzada com Go, confira meu tutorial anterior sobre o assunto.

Como parte de um requisito do Lambda, o arquivo binário deve ser compactado em ZIP. Anote o nome do arquivo e adicione-o a um arquivo ZIP na raiz do diretório. O nome do arquivo binário representa o nome do manipulador.

Em seguida, acesse o Console do Desenvolvedor da AWS e escolha criar uma nova função Lambda. O nome não é muito importante, apenas certifique-se de que ela esteja usando o runtime Go.

AWS Developer ConsoleAWS Developer Console

No painel dessa função específica, selecione o arquivo ZIP que você acabou de criar para fazer o upload. Lembre-se de informar o nome de arquivo correto nas informações do manipulador.

Também vamos adicionar o API Gateway como um gatilho para a função.

Acesse a seção do API Gateway no AWS Developer Console. É aqui que será criado um endpoint público para apontar para a função. No painel do API Gateway, selecione “Criar método” na seção guia .

Create MethodCreate Method

O método criado deve ser uma solicitação POST e deve indicar o valor do ARN da função AWS Lambda quando solicitado. Ao concluir, não se esqueça de implantar a API pelo mesmo menu usado para criar um novo método.

Neste momento, a função Lambda já deve estar acessível por meio do API Gateway que foi configurado. Podemos obter a URL por meio das guia “Stages” , caso não haja um domínio personalizado configurado.

Conclusão

Acabamos de ver como enviar mensagens para dispositivos móveis usando o AWS Lambda e a linguagem de programação Go. Resumindo, se um usuário fizesse uma solicitação à API, gerenciada pelo API Gateway, a solicitação seria encaminhada para o AWS Lambda, enviada ao Nexmo e, em seguida, enviada ao dispositivo do usuário. Um caso de uso, como mencionado anteriormente, poderia ser o envio do link da loja de aplicativos — seja do Google Play ou do iTunes — para o celular do usuário por SMS.

Embora isso não tenha sido abordado neste exemplo, podemos facilmente ampliar este projeto criando uma interface de usuário para que os usuários possam interagir, em vez de nos limitarmos estritamente a uma API RESTful.

Compartilhar:

https://a.storyblok.com/f/270183/384x384/5b89273998/nraboy.png
Nic Raboy