AWS Serverless: 3 aspectos importantes ao projetar uma API Serverless
Eduardo Rabelo
Posted on April 18, 2020
Já se passaram três meses do ano 2020 e todo o mundo da tecnologia está adotando a computação serverless. Segundo o relatório Tech Trends 2020 da Nasdaq, "[computação serverless] está reduzindo os custos de capital e mudando o foco para as necessidades dos clientes, ao invés de instalar, configurar, aplicar patches e manter servidores no data center".
A computação serverless pode ser e está sendo usada em muitos casos de uso técnico, com ganhos significativos em relação à abordagem tradicional baseada em servidor. Um desses casos de uso é o desenvolvimento de APIs HTTP. Nos dias pré-servidor, o desenvolvimento de uma API incluía muitas responsabilidades; desenvolvendo a lógica de negócios real, configurando um servidor web adequado, gerenciando deploys do servidor, protegendo as APIs e cuidando da disponibilidade e da escalabilidade da API ao longo do dia. Porém, com a erupção das tecnologias serverless, a maioria dessas responsabilidades é assumida pelo provedor de serviços em nuvem e o desenvolvedor tem a flexibilidade de simplesmente se concentrar na lógica de negócios real das APIs.
Neste artigo, vamos primeiro analisar brevemente os serviços relacionados ao desenvolvimento de APIs fornecidos pelo provedor de serviços em nuvem mais popular, Amazon Web Services (AWS), e discutir três dos aspectos mais importantes a serem considerados ao projetar e implantar APIs que utilizam esses serviços.
API Serverless com Amazon Web Services (AWS)
Na AWS, a criação de uma API serverless envolve dois serviços, que são o AWS API Gateway e o AWS Lambda. O AWS API Gateway pode ser usado para gerenciar os endpoints da API e cuida completamente da manipulação de solicitação-resposta no nível HTTP. Além disso, o API Gateway fornece os recursos para gerenciar versões da API com estágios, recursos de segurança da API com vários tipos de mecanismos de autorização e também diferentes tipos de controles de limitação de solicitação da API.
Em seguida, as funções do AWS Lambda podem ser utilizadas para lidar com a lógica comercial dessas chamadas de API recebidas pelos endpoints do API Gateway. Cada endpoint do API Gateway pode ser integrado ao Lambda como um acionador para que, quando uma solicitação for recebida por um endpoint específico, a função Lambda configurada seja invocada com os detalhes da solicitação. Em seguida, a função Lambda pode processar a solicitação e retornar uma resposta adequada ao API Gateway. O API Gateway gerará a resposta HTTP com base nisso e a enviará de volta ao cliente que chamou a API.
Agora, vamos ver três dos aspectos mais importantes a serem observados ao criar APIs com esses serviços.
1. Mapeando endpoints do API Gateway para funções do AWS Lambda
Uma das decisões de design mais críticas a serem tomadas quando uma API sem servidor é projetada é como os endpoints da API podem ser mapeados para as funções do AWS Lambda para processar as solicitações. Vamos examinar duas das abordagens mais usadas.
Vamos considerar uma API de uma loja de varejo on-line para discutir essas abordagens. Essa API será usada para gerenciar recursos, como usuários, itens de varejo e compras, enquanto cada um desses recursos terá vários endpoints e métodos para diferentes operações.
1.1. Abordagem 1: Uma lambda por recurso
Nesta abordagem, todas as solicitações para um recurso específico serão direcionadas para a mesma função Lambda. Em seguida, na função Lambda, essas solicitações serão redirecionadas para diferentes ramificações de processamento com base na operação solicitada. Por exemplo, uma solicitação para criar um novo usuário e uma solicitação para recuperar detalhes de um usuário existente chamarão a mesma função Lambda. Uma solicitação para atualizar um item listado e uma solicitação para obter uma lista dos itens disponíveis chamarão outra função Lambda. Em seguida, o código Lambda invocado identificará a operação solicitada e a processará de acordo. Uma biblioteca como o AWS Serverless Express pode ser utilizada para executar esse roteamento interno com facilidade e eficiência.
Vantagens
- Menor número de funções Lambda a serem gerenciadas
- Fácil de reutilizar códigos, bibliotecas e utilitários comuns específicos de recursos entre operações
- Modificações em todo o recurso requerem a atualização de apenas uma função Lambda
Desvantagens
- Uma atualização para uma única operação pode afetar todas as operações na mesma função Lambda
- O roteamento em dois níveis (primeiro no nível do API Gateway e, em seguida, no nível interno do lambda) pode introduzir uma sobrecarga
- A mesma função lambda deve ser concedida para ter todas as permissões de execução necessárias para cada operação, o que pode ser um risco à segurança
- Não é possível ajustar os parâmetros da função Lambda, como memória, tempo limite e execuções simultâneas com base na operação
- Se houver bibliotecas específicas da operação, todas elas serão carregadas, independentemente da operação a ser executada, o que pode estender o tempo de inicialização a frio do Lambda
1.2. Abordagem 2: Uma lambda por operação
Nesta abordagem, há uma função Lambda separada para cada operação de cada recurso. Por exemplo, uma solicitação para criar um novo usuário será processada por uma função Lambda, enquanto uma solicitação para recuperar detalhes de um usuário existente será processada por outra. Nesse caso, não há necessidade de um mecanismo de roteamento interno e o roteamento é completamente executado no nível do API Gateway.
Vantagens
- Cada operação pode ser atualizada e testada independentemente, sem afetar outras operações
- A função Lambda deve receber apenas as permissões mínimas de execução para a operação específica
- Os parâmetros da função Lambda, como memória, tempo limite e execuções simultâneas, podem ser ajustados com base na operação
- Cada função Lambda exige carregar apenas as bibliotecas necessárias para a operação pretendida
Desvantagens
- Grande número de funções Lambda a serem gerenciadas
- Modificações em todo o recurso requerem a atualização de várias funções Lambda
- A reutilização de códigos comuns específicos de recursos, bibliotecas e utilitários entre operações exigirá medidas adicionais, como publicá-las como módulos Node.js ou Lambda Layers
Como mencionado acima, ambas as abordagens têm suas próprias vantagens e desvantagens do ponto de vista do desempenho e do ponto de vista do gerenciamento de código e deploy. Portanto, é nossa responsabilidade escolher a abordagem apropriada com base em nossos requisitos e caso de uso.
2. Temos dois tipos de integração: lambda e lambda-proxy
O AWS API Gateway fornece duas maneiras principais de integrar seus endpoints a funções Lambda. Com base nas informações exigidas pela função Lambda para processar a solicitação, precisamos selecionar um desses métodos de integração para cada um dos nossos métodos de integração do API Gateway-Lambda.
2.1. Integração 1: Lambda
O primeiro método é o método de integração regular do Lambda (no API Gateway teremos "type": "aws"
), no qual o API Gateway encaminha apenas o payload da solicitação para a função Lambda como evento. Em seguida, a função Lambda também é obrigada a enviar apenas o payload da resposta ao API Gateway. Nos casos em que a função Lambda precisa apenas do payload da solicitação para processar a solicitação, podemos usar esse método de integração.
2.2. Integração 2: Lambda-Proxy
O segundo método é a integração do Lambda Proxy (no API Gateway teremos "type": "aws_proxy"
), na qual o API Gateway encaminha os detalhes completos da solicitação HTTP para a função Lambda, incluindo:
- cabeçalhos da requisição
- parâmetros de caminho
- parâmetros de query string
- detalhes do recurso e requisição
- informação do stage do API Gateway
- e, claro, o payload
Em seguida, a função Lambda também é responsável por enviar de volta os cabeçalhos de resposta e o código de status, além da carga útil da resposta. Nos casos em que a função Lambda precisa das informações e valores do cabeçalho e parâmetros de caminho/query string para seu processamento, podemos usar esse método de integração.
3. Autenticação da API
O controle de acesso e a autenticação são outro fator importante a ser considerado ao projetar não apenas APIs serverless, mas também qualquer tipo de API. Portanto, o AWS API Gateway também fornece os seguintes mecanismos para autenticação e autorização:
- Políticas de Recursos (Resource Policies)
- Funções e Políticas padrão do AWS IAM (IAM Roles and Policies)
- Tags IAM
- Políticas de Endpoints para se comunicar com VPC Endpoints (Endpoint Policies)
- Autorizadores Lambda (Lambda Authorizers)
- Pools de usuários do Amazon Cognito
Desses, os dois últimos mecanismos são amplamente usados com as APIs serverless no API Gateway. Portanto, vamos ver brevemente o que esses dois mecanismos oferecem.
3.1. Pools de usuários do Amazon Cognito
Se estivermos usando o serviço AWS Cognito para gerenciamento de usuários, esse mecanismo é a maneira mais conveniente e eficiente de autenticar solicitações de API. Quando esse mecanismo é usado, precisamos criar um autorizador no API Gateway especificando quais pools de usuários do Cognito devem ser usados para conceder acesso a essa API. Em seguida, o cliente deve enviar um token de ID válido do Cognito (ou token de Acesso, dependendo da configuração) como um cabeçalho HTTP da solicitação. Normalmente, isso deve ser enviado como o cabeçalho Authorization
, mas é possível configurar o autorizador para usar também qualquer outro cabeçalho personalizado.
Depois que essa solicitação é recebida pelo API Gateway, ele usa esse token para autenticar o usuário com o pool de usuários do Cognito. Se a autenticação for bem-sucedida, a função Lambda relevante será invocada como de costume. Se a integração Lambda-Proxy for usada, os detalhes do usuário decodificados do token também serão incluídos no evento passado para o Lambda, portanto, é muito conveniente e útil executar operações específicas do usuário. Caso a autenticação falhe, o próprio API Gateway envia de volta uma resposta 401 Unauthorized
, sem chamar a função Lambda.
3.2. Autorizadores Lambda (Lambda Authorizers)
Nesse mecanismo, precisamos configurar uma função Lambda exclusiva para autenticação e criar um autorizador no API Gateway apontando para ela. Existem 2 tipos de autorizadores Lambda.
- Baseados em Token (Autorizador TOKEN): Esse tipo de autorizador recebe a identidade do chamador em um token bearer, como um JSON Web Token (JWT) ou um token OAuth.
- Baseado em Parâmetros (Autorizador REQUEST): Este tipo de autorizador recebe a identidade do chamador como uma combinação de cabeçalhos, query string de consulta, variáveis de estágio e variáveis de contexto.
Depois que uma solicitação é recebida pelo API Gateway, ele primeiro chama a função Lambda do autorizador com os detalhes da solicitação. Em seguida, o autorizador do Lambda autentica o chamador usando um mecanismo de etapas como:
- chamando um provedor OAuth para obter um token de acesso OAuth
- chamando um provedor SAML para obter uma asserção SAML
- gerando uma política do IAM com base nos valores dos parâmetros de solicitação
- recuperando credenciais de um banco de dados
Se a autenticação for bem-sucedida, a função Lambda deverá conceder acesso retornando um objeto de saída que contenha pelo menos uma política IAM (IAM Policy) e um identificador principal (principal identifier).
Em seguida, o API Gateway avalia a política e, se o acesso for permitido, a função Lambda será invocada a seguir. Se o armazenamento em cache estiver ativado nas configurações do autorizador, o API Gateway também armazenará em cache a política para que a função do autorizador Lambda não precise ser chamada novamente. Caso a autenticação falhe, o API Gateway retornará um código de status HTTP adequado, como 403 ACCESS_DENIED
.
Finalizando
Portanto, como discutido acima, esses são três dos aspectos mais importantes a serem considerados ao projetar uma API serverless. Se pudermos escolher ou configurá-los adequadamente, isso tornará o gerenciamento e a manutenção das APIs mais eficientes e convenientes.
Créditos
- 3 Things to consider when designing a Serverless API, escrito originalmente por Udith Gunaratna.
Posted on April 18, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.