Criando um encurtador de URL Serverless e Codeless com API Gateway e DynamoDB

Flávio Losada
Senior Sistemas
Published in
13 min readAug 20, 2020

Este artigo foi desenvolvido em colaboração com o Leonardo Fiedler, se baseando em três artigos publicados no blog da AWS.

O objetivo deste passo a passo, é demonstrar como desenvolver um encurtador de URL, com a possibilidade de personalizar o link de acordo com a necessidade do usuário. Trabalhando em uma solução serverless e com o mínimo de código utilizando ferramentas como AWS API Gateway e AWS DynamoDB.

O encurtador será acessado por meio de requisições HTTP, não há intenção de desenvolver interface visual nesse momento.

É importante ressaltar que será necessária uma conta Amazon AWS para execução deste tutorial. É possível completar toda esta implementação de forma gratuita na AWS, porém não recomendamos que o serviço continue ativo por muito tempo, ele pode acarretar em custos.

O problema

Alguns meios de comunicação tem um número limitado de caracteres que podem ser utilizados em uma publicação ou comentário. O Twitter por exemplo, limita em 280 caracteres por Tweet.

Além disso, um link muito longo, com caracteres especiais, traços, percentuais, entre outros, pode tornar uma publicação desagradável visualmente. Por fim, uma URL encurtada com link personalizado pode facilitar a memorização.

A solução

Pensando no problema, há tempos foram criados os encurtadores de link que tem o objetivo de transformar uma URL muito longa em um link curto que pode ser compartilhado ocupando menos caracteres e deixando a publicação com uma aparência mais agradável.

A ideia de criar o próprio encurtador de link, surgiu quando foram fazer a divulgação de vagas de emprego em nossa empresa. Os links eram muito extensos e com diversos caracteres especiais. Então, o intuito é utilizar um domínio específico personalizado, remetendo a empresa e encurtar essas URLs.

Agora vamos por a mão na massa! O tutorial está organizado conforme o índice abaixo.

Índice

  • Encurtador de URL — Tecnologias utilizadas
    - Mas não era Codeless?
  • AWS DynamoDB
  • Permissões
    - Porque UpdateItem?
    - Função do IAM
  • AWS API Gateway
    -
    Inserindo uma nova URL
    - Acessando um alias e redirecionando
  • Implantando o encurtador de links
    - Deploy
    - Testes
    - Mas a minha URL não está tão curta assim!
  • Conclusão

Encurtador de URL

As seguintes tecnologias serão usadas como base:

  • AWS API Gateway: responsável pelos endpoints para criar uma URL encurtada e fazer o redirecionamento ao acessar uma URL encurtada.
  • AWS DynamoDB: armazena a lista de URLs já encurtadas, será consumido pelo AWS API Gateway.

As tecnologias da AWS serão utilizadas por meio do console visual. A região da AWS também é muito importante. Neste caso recomendamos o uso da região us-east-1 (Norte da Virgínia). O motivo é que esta região tem mais recursos disponíveis e caso opte por trabalhar com AWS Cognito por exemplo, o recurso já está ativo na região.

Além disso, será utilizado Apache VTL para o código.

Mas não era Codeless?

Sim! O objetivo aqui é não escrever código-fonte! A Apache VTL será utilizada apenas para converter o payload da requisição enviada ao API Gateway em um payload que o DynamoDB consiga entender.

Sem mais delongas, vamos à prática!

AWS DynamoDB

O DynamoDB será nosso banco de dados NoSQL, onde teremos a relação da URL encurtada com a URL original. Além disso, é possível definir outros campos como autor ou então o recurso de tempo de expiração do registro, que você pode encontrar na documentação.

Vamos criar nossa tabela!

Tabela url-shortener

Para as configurações da tabela, desmarque a opção “Usar configurações padrão” e vamos configurar manualmente!

Configurações da tabela

Mantenha o modo de capacidade como “Provisionada” e desmarque as opções de “Capacidade de leitura” e “Capacidade de gravação” no item Auto Scalling.

Auto Scalling

Acima de “Auto Scalling”, em “Capacidade provisionada” definiremos os valores de acordo com o uso do recurso encurtador de URL. Para uma primeira versão podemos definir as Unidades de capacidade de leitura e gravação como 1. Para mais informações sobre estes campos, consulte a documentação sobre definição de preço.

Capacidade provisionada

Agora podemos criar nossa tabela, clicando em Criar!

Permissões

Com a tabela criada, é necessário criar as funções e políticas para conceder acesso à tabela por meio de outros recursos da AWS.

Nesta etapa será criada uma função com uma política personalizada. Para saber mais sobre funções e políticas do AWS IAM, consulte a documentação.

Acesse o serviço AWS IAM, vá até “Políticas” e clique em “Criar política”.

Criar política

Em “Serviço”, selecione a opção DynamoDB.

Para “Ações”, no item “Leitura” marque a opção: GetItem. No item “Gravação” marque as opções: UpdateItem e DeleteItem.

Em “Recursos” deve ser definida a tabela que deseja acessar. Clique em “Adicionar ARN” e informe os campos conforme solicitado (O campo Account não deve ser modificado).

Adicionar ARN

Clique em “Revisar política” e dê o nome e descrição.

Revisar política

Clique em “Criar política!”

Por que UpdateItem?

Beleza, mas se queremos criar uma URL encurtada e armazenar no DynamoDB, por que não selecionamos a permissão ao comando “PutItem”, somente ao comando “UpdateItem”?

Normalmente, utilizamos o comando “PutItem” para inserir novos registros em uma tabela no DynamoDB, mas acontece que o comando “PutItem” não retorna todo o registro que acabou de ser inserido na tabela, obrigando em muitos casos a fazer uma nova consulta à tabela para obter o restante da informação.

Como o exemplo utiliza API Gateway se comunicando diretamente com o DynamoDB, não é possível fazer uma segunda interação com a tabela para obter estes dados e retorná-los pela API. Por este motivo, é utilizado o comando “UpdateItem” que ao ser executado, retorna todo o registro que acabou de ser atualizado e caso o registro ainda não exista, será inserido!

Função do IAM

A função do IAM, é a configuração que de fato dará permissão para um recurso AWS ter acesso a outros recursos. Uma função do IAM pode ter várias políticas, que dão permissões a recursos diferentes. Para saber mais sobre funções do IAM, acesse a documentação.

A função do IAM criada terá duas políticas, uma que terá permissões para gravação de logs e a outra será a política personalizada criada anteriormente. Para isso, vá até o item “Funções” no serviço IAM e clique em “Criar função”.

Criar função

Na tela apresentada, selecione o serviço “API Gateway”, pois este serviço que deve acessar a tabela do DynamoDB.

Serviço API Gateway

Mantenha o caso de uso selecionado e vá até botão “Próximo: Permissões”.

Caso de uso

Clique em “Próximo: Tags” e depois em “Próximo: Revisar”.

Dê um nome e descrição à função

Nome e descrição

Clique em “Criar função”.

Procure pela função que acabou de ser criada, utilize o campo de pesquisa se necessário.

Pesquisa função

Acesse a função e vá em “Anexar políticas”. Pesquise pela política personalizada que foi criada anteriormente e anexe.

Anexar política

AWS API Gateway

O serviço API Gateway permite criar uma API, seja ela HTTP, WebSocket, REST (utilizado neste tutorial) com a finalidade de direcionar as requisições a outros serviços da AWS.

Acesse o serviço e selecione a opção API REST. Cuidado para não selecionar a opção API REST privada. Selecione o protocolo “REST” e a opção “API nova”. Dê um nome à API e a descrição (opcional) e clique em “Criar API”!

Criar API

Inserindo uma nova URL

Em “Recursos” vá até “Ações” e selecione a opção “Criar recurso”.

Criar recurso

Dê um nome ao recurso e o caminho — por padrão é utilizado o mesmo valor — e clique em “Criar recurso”.

Vá em “Ações” e selecione a opção “Criar método”, selecionando o método “POST”.

Método POST

Ao selecionar o método “POST”, informe os seguintes campos:

  • Tipo de Integração: Serviço da AWS
  • Região da AWS: Código da região escolhida, por exemplo, us-east-1
  • Serviço da AWS: DynamoDB
  • Método HTTP: POST
  • Tipo de ação: Usar nome da ação
  • Ação: UpdateItem
  • Função de execução: Informe o ARN da função do IAM que foi criada, por exemplo: arn:aws:iam::123456789:role/APIGatewayLogsAndDynamoDB. Para encontrar o ARN da função, acesse a função via IAM.

Clique em “Salvar”.

Neste momento a API está criada, agora ela deverá ser configurada para comunicar-se com DynamoDB. Crie um modelo para validação do JSON recebido pela API. Para isto, vá até o item “Modelos” no painel à esquerda.

Modelos

Crie um novo modelo, dê o nome de “ValidadorJSON”. Em “Tipo de conteúdo”, informe application/json. Em “Esquema do modelo” informe o trecho abaixo:

{
"required" : [ "id", "url" ],
"type" : "object",
"properties" : {
"id" : { "type" : "string"},
"url" : {
"pattern" : "^https?://[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,6}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)",
"type" : "string"
}
}
}

O trecho acima contém a validação para o JSON que será recebido pela API, garantindo que o conteúdo enviado esteja correto para assim ser transformado e inserido no DynamoDB. Clique em “Criar modelo”.

Voltando ao item “Recursos” no painel esquerdo, selecione novamente o item “POST”.

Recursos — POST

Clique sobre “Solicitação de método”.

Solicitação de método

No item “Corpo da solicitação” clique em “Adicionar modelo”, informe o “Tipo de conteúdo” e o “Nome do modelo” que foi criado anteriormente. Confirme clicando no botão destacado.

Corpo da solicitação

Volte a tela anterior e vá até “Solicitação de integração”. Em “Modelos de mapeamento selecione a opção “Quando não há modelos definidos (recomendado)” e adicione o “Content-Type” application/json.

Modelos de mapeamento

Logo abaixo, preencha o campo abaixo de “Gerar modelo” com o código a seguir:

{
"TableName": "url-shortener",
"ConditionExpression":"attribute_not_exists(id)",
"Key": {
"id": { "S": $input.json('$.id') }
},
"ExpressionAttributeNames": {
"#u": "url",
"#ts": "timestamp"
},
"ExpressionAttributeValues":{
":u": {"S": $input.json('$.url')},
":ts": {"S": "$context.requestTime"}
},
"UpdateExpression": "SET #u = :u, #ts = :ts",
"ReturnValues": "ALL_NEW"
}

O código acima, trata-se do JSON que será enviado ao DynamoDB para inserir o registro na tabela. Neste trecho de código, é utilizada a Apache VTL, comentada anteriormente, para obter informações do payload que foi enviado ao API Gateway e outras informações. Clique em “Salvar”.

Até aqui, foram configuradas as etapas que tratam da mensagem recebida pelo serviço API Gateway e a mensagem que é enviada ao DynamoDB. Nos próximos passos será configurado o retorno do serviço DynamoDB até o retorno da API para a origem da requisição.

Volte a tela anterior e vá até “Resposta de método” e clique em “Adicionar resposta” informando os campos a seguir:

  • Código de status HTTP: 400
Código de status HTTP

Volte a tela anterior e vá até “Resposta de integração”, clique em “Adicionar resposta de integração”, preencha os campos abaixo:

  • Regex de status HTTP: 400
  • Status de resposta de método: 400
  • Manuseio de conteúdo: Passagem

Clique em “Salvar” e selecione o registro que foi criado. Clique na opção Modelos de mapeamento e adicione um novo modelo.

Modelos de mapeamento

Para o campo Content-Type informe application/json.Clique no botão para gravar e no campo ao lado que aparecerá, informe o código abaixo:

#set($inputRoot = $input.path('$')) 
#if($inputRoot.toString().contains("ConditionalCheckFailedException"))
#set($context.responseOverride.status = 200)
{"error": true,"message": "URL link already exists"}
#end

O código acima retornará uma mensagem de erro caso seja informado uma rota/alias — rota ou “alias” é o apelido que será utilizado na URL encurtada — já existente para uma URL. Clique em “Salvar”.

Acessando um alias e redirecionando

Novamente na árvore de recursos, no botão “Ações” crie um novo recurso com nome “linkId” e parâmetro “{linkId}”, conforme imagem abaixo:

Recurso linkId

Selecione o recurso criado, vá até o botão Ações e crie um método do tipo “GET”. Na tela ao lado, informe os campos conforme valores a seguir:

  • Tipo de integração: Serviço da AWS
  • Região da AWS: Informe a região selecionada para criação deste projeto, por exemplo us-east-1
  • Serviço da AWS: Informe o serviço DynamoDB
  • Método HTTP: POST — Aqui é o método que será enviado ao DynamoDB, portanto deve ser o método POST.
  • Ação: GetItem
  • Função de execução: Informe a função do IAM que criada anteriormente e já utilizada no método POST.

Clique em “Salvar”.

Na tela apresentada, vá em “Solicitação de integração”, selecione o item “Modelos de mapeamento”. Marque a opção “Quando não há modelos definidos (recomendado)” e adicione um modelo de mapeamento com “Content-Type” application/json.

Modelos de mapeamento

Logo abaixo, no campo disponível informe o código a seguir:

{"Key": 
{"id":
{"S": "$input.params().path.linkid"}
},
"TableName": "url-shortener"
}

Este trecho utilizará do parâmetro recebido na requisição para obter a URL de destino armazenada no DynamoDB. Clique em “Salvar”.

Volte a tela anterior e vá em “Resposta do método”. Adicione uma nova resposta. Informe o código “301” e salve.

Código de status HTTP

Selecione o registro que foi inserido. Em “Cabeçalhos de resposta de 301”, adicione os itens “Location” e “Cache-Control”.

Cabeçalhos de resposta de 301

Volte a tela anterior e vá até “Resposta de integração”. Remove o registro existente e adicione um novo registro conforme campos abaixo:

  • Regex de status HTTP: Deixar em branco (default)
  • Status de resposta de método: 301
  • Manuseio de conteúdo: Passagem

Clique em “Salvar”. Selecione o registro inserido e vá em “Modelos de mapeamento”. Adicione um novo modelo de mapeamento com o “Content-Type” application/json. No campo apresentado, informe o código a seguir:

#set($inputRoot = $input.path('$'))
#if($inputRoot.toString().contains("Item"))
#set($context.responseOverride.header.Location = $inputRoot.Item.url.S)
#end

O código acima é utilizado para tratar o retorno fornecido pelo DynamoDB, obtendo a URL armazenada no banco de dados e utilizando-a para redirecionar o usuário. Clique em “Salvar”.

Implantando o encurtador de links

As etapas de configurações foram concluídas, agora o encurtador pode ser implantando para ser testado.

É importante salientar que não foram feitas configurações de proteção, portanto, ao fazer deploy da API seu serviço ficará disponível na web, não recomendamos que o serviço seja exposto desta forma por muito tempo.

Para gerenciar o controle de acesso a API, recomendamos a leitura da documentação.

Deploy

No botão “Ações” selecione a opção “Implantar API” e preencha os campos:

Implantar

Clique em “Implante”!

Será direcionado ao item “Estágios” na árvore à esquerda da tela. Uma URL será disponibilizada para acesso a API.

URL

Testes

Ok! API implantada! Mas como eu testo?

Como não foi desenvolvido nenhum aplicativo de frontend para se comunicar com a API, utilizaremos dos métodos HTTP e do navegador de internet para interagir com o encurtador.

O primeiro passo é encurtar uma URL, ou seja, inserir um registro no banco de dados. Nesta etapa recomendamos o uso de uma ferramenta para auxiliar na execução do método POST, como Postman ou Talend API.

Escolhida a ferramenta, vamos aos testes! Vamos utilizar o Postman nos exemplos.

Informe a URL da sua API e o caminho que será enviado a requisição. No caso deste tutorial: /shortener.

Altere o método para “POST” e nos cabeçalhos (headers) informe o Content-Type como application/json.

Método POST

Em “Body”, selecione a opção “raw” e informe o JSON conforme modelo abaixo:

{"id": "casa-campo","url": "https://www.google.com/url?sa=i&url=https%3A%2F%2Fwallhere.com%2Fpt%2Fwallpaper%2F165846&psig=AOvVaw2yyUA96wxwAVbOtf9deOQn&ust=1597870378251000&source=images&cd=vfe&ved=0CAIQjRxqFwoTCJC-55XRpesCFQAAAAAdAAAAABAD"}

No campo “id”, informe qual será o alias para sua URL. No campo “url” informe a URL que deseja encurtar.

Feito isso, envie sua requisição!

Agora vamos testar o redirecionamento! Com a URL gerada pelo API Gateway, copie e cole no seu navegador e adicione o alias que você acabou de criar, no meu caso seria:

URL encurtada

Pressione enter e veja a mágica acontecer!

It’s MAGIC!

Mas a minha URL não está tão curta assim!

Ok, tens razão. A URL gerada pelo API Gateway não é tão curta como o esperado. Mas como resolver?

Bom, basicamente será necessário adquirir domínios que sejam curtos, alguns exemplos são:

A partir daí, basta configurar o serviço da AWS para que sua API fique dentro do seu domínio. Recomendamos a leitura da documentação.

Conclusão

É possível criar a base de um encurtador de URLs utilizando recursos serverless da AWS e praticamente sem código-fonte. A partir deste tutorial foi possível implementar este encurtador e testá-lo.

Alguns refinamentos ainda ficam pendentes, mas o tutorial cumpre seu papel. Possíveis melhorias que poderiam ser adicionadas são:

  • adicionar segurança na API, exigindo um usuário logado e/ou uma chave de API para uso desta;
  • adquirir um domínio próprio e configurá-lo para que a URL fique realmente curta;
  • implementar um aplicativo de frontend que permitirá que o usuário final acesse a API e encurte suas URLs;
  • permitir que sejam excluídas URLs já encurtadas anteriormente;
  • adicionar uma função Lambda para permitir que sejam geradas URLs aleatórias, sem um alias informado pelo usuário.

Entre outras mudanças ou melhorias são possíveis.

--

--