Se preferir assistir e aprender, você pode conferir o vídeo abaixo:

Começando

Para iniciar todo esse processo, precisamos nos certificar de que temos o Serverless Framework instalado e um perfil AWS configurado em nosso computador. Se não, então você pode confira este video sobre como configurar tudo.

Se você quiser acompanhar este tutorial, você pode seguir todas as etapas ou baixe o código aqui e siga com o código completo.

Agora estamos criando nosso projeto sem servidor e API. Precisamos começar em um terminal e executar o comando para criar nosso novo repo. Tudo que você precisa fazer é trocar o {YOUR FOLDER NAME} para o nome da sua pasta.

serverless create --template aws-nodejs-typescript --path {YOUR FOLDER NAME}

Isso criará um projeto sem servidor muito básico com TypeScript. Se abrirmos esta nova pasta com o VS Code, então podemos ver o que o modelo nos deu.

Screenshot 2020 08 21 at 06.54.45

Os principais arquivos que queremos analisar são os serverless.ts arquivo e o handler.ts Arquivo.

o serverless.ts arquivo é onde a configuração para a implantação é realizada. Este arquivo informa ao framework sem servidor o nome do projeto, a linguagem de tempo de execução do código, a lista de funções e algumas outras opções de configuração.

Sempre que quisermos mudar a arquitetura de nosso projeto, este é o arquivo no qual estaremos trabalhando.

O próximo arquivo é o handler.ts Arquivo. Aqui temos o código de exemplo para um lambda fornecido a nós pelo modelo. É muito básico e apenas retorna uma resposta do API Gateway com uma mensagem e o evento de entrada. Usaremos isso mais tarde como um bloco inicial para nossa própria API.

Crie seu próprio Lambda

Agora que vimos o que temos com o modelo, é hora de adicionar nosso próprio Lambda e endpoint de API.

Para começar, vamos fazer uma nova pasta para armazenar todo o nosso código lambda e chamá-la lambdas. Isso ajuda a organizá-lo, especialmente quando você começa a obter alguns lambdas diferentes em um projeto.

Nessa nova pasta, vamos criar nosso novo lambda, chamando-o getCityInfo.ts. Se abrirmos este arquivo, podemos começar a criar nosso código. Podemos começar copiando todos os handler.ts código como ponto de partida.

A primeira coisa que vamos fazer é mudar o nome da função para handler. Esta é uma preferência pessoal, mas gosto de nomear a função que trata o manipulador de eventos.

Na primeira linha desta função, precisamos adicionar algum código para obter a cidade que o usuário está solicitando. Podemos obter isso no caminho do URL usando pathParameters.

const city = event.pathparameter?.city;

Uma coisa que você pode notar é o uso de ?. nessa declaração. Esse é o encadeamento opcional e é um recurso muito legal. Eu

t significa se o parâmetro do caminho for verdadeiro, obtenha o parâmetro da cidade, caso contrário, retorne indefinido. Isso significa se pathParameter não era um objeto, isso não iria conseguir o cannot read property city of undefined erro que causa um erro no tempo de execução do Nó.

Agora que temos a cidade, precisamos verificar se a cidade é válida e se temos os dados dessa cidade. Para isso, precisamos de alguns dados. Podemos usar o código abaixo e colar no final do arquivo.

interface CityData {    name: string;    state: string;    description: string;    mayor: string;    population: number;    zipCodes?: string;}const cityData: { [key: string]: CityData } = {    newyork: {        name: 'New York',        state: 'New York',        description:            'New York City comprises 5 boroughs sitting where the Hudson River meets the Atlantic Ocean. At its core is Manhattan, a densely populated borough that’s among the world’s major commercial, financial and cultural centers. Its iconic sites include skyscrapers such as the Empire State Building and sprawling Central Park. Broadway theater is staged in neon-lit Times Square.',        mayor: 'Bill de Blasio',        population: 8399000,        zipCodes: '100xx–104xx, 11004–05, 111xx–114xx, 116xx',    },    washington: {        name: 'Washington',        state: 'District of Columbia',        description: `DescriptionWashington, DC, the U.S. capital, is a compact city on the Potomac River, bordering the states of Maryland and Virginia. It’s defined by imposing neoclassical monuments and buildings – including the iconic ones that house the federal government’s 3 branches: the Capitol, White House and Supreme Court. It's also home to iconic museums and performing-arts venues such as the Kennedy Center.`,        mayor: 'Muriel Bowser',        population: 705549,    },    seattle: {        name: 'Seattle',        state: 'Washington',        description: `DescriptionSeattle, a city on Puget Sound in the Pacific Northwest, is surrounded by water, mountains and evergreen forests, and contains thousands of acres of parkland. Washington State’s largest city, it’s home to a large tech industry, with Microsoft and Amazon headquartered in its metropolitan area. The futuristic Space Needle, a 1962 World’s Fair legacy, is its most iconic landmark.`,        mayor: 'Jenny Durkan',        population: 744955,    },};

A diferença entre isso e o JavaScript é que podemos criar um interface para dizer ao sistema qual deve ser a estrutura dos dados. Isso parece um trabalho extra no início, mas ajudará a tornar tudo mais fácil mais tarde.

Dentro de nossa interface, definimos as chaves do objeto cidade; alguns que são strings, um número e depois o zipCodes é uma propriedade opcional. Isso significa que pode estar lá, mas não precisa estar.

Se quisermos testar nossa interface, podemos tentar adicionar uma nova propriedade a qualquer uma das cidades em nossos dados de cidade.

O TypeScript deve informar instantaneamente que sua nova propriedade não existe na interface. Se você excluir uma das propriedades necessárias, o TypeScript também reclamará. Isso garante que você sempre tenha os dados corretos e os objetos sempre com a aparência exatamente como o esperado.

Agora que temos os dados, podemos verificar se o usuário enviou a solicitação de cidade correta.

if (!city || !cityData[city]) {    }

Se esta afirmação for verdadeira, o usuário fez algo errado, portanto, precisamos retornar uma resposta 400.

Poderíamos apenas digitar manualmente o código aqui, mas vamos criar um novo apiResponses objeto com métodos para alguns dos códigos de resposta de API possíveis.

const apiResponses = {    _200: (body: { [key: string]: any }) => {        return {            statusCode: 200,            body: JSON.stringify(body, null, 2),        };    },    _400: (body: { [key: string]: any }) => {        return {            statusCode: 400,            body: JSON.stringify(body, null, 2),        };    },};

Isso apenas torna muito mais fácil reutilizar posteriormente no arquivo. Você também deve ver que temos uma propriedade de body: { [key: string]: any }. Isso está afirmando que essa função tem uma propriedade de corpo que precisa ser um objeto. Esse objeto pode ter chaves com um valor de qualquer tipo.

Porque sabemos disso body sempre será uma string que podemos usar JSON.stringify para garantir que retornamos um corpo de string.

Se adicionarmos esta função ao nosso manipulador, obteremos o seguinte:

export const handler: APIGatewayProxyHandler = async (event, _context) => {    const city = event.pathParameters?.city;    if (!city || !cityData[city]) {        return apiResponses._400({ message: 'missing city or no data for that city' });    }    return apiResponses._200(cityData[city]);};

Se o usuário não passou uma cidade ou uma para a qual não temos dados, retornamos 400 com uma mensagem de erro. Se os dados existirem, retornamos 200 com o corpo dos dados.

Na seção anterior, configuramos nosso repositório TypeScript API e criamos um lambda que apenas usava dados codificados.

Esta parte vai te ensinar como usar o aws-sdk para interagir diretamente com outros serviços da AWS para criar uma API realmente poderosa.

Para começar, precisamos adicionar um novo arquivo para nossa API de tradução. Crie um novo arquivo no lambdas pasta chamada translate.ts. Podemos começar este arquivo com algum código básico padrão. Este é o código inicial para um Lambda API TypeScript.

import { APIGatewayProxyHandler } from 'aws-lambda';import 'source-map-support/register';export const handler: APIGatewayProxyHandler = async (event) => {    };

Agora precisamos obter o texto que o usuário deseja traduzir e o idioma para o qual deseja traduzir. Podemos obtê-los no corpo da solicitação.

Uma coisa extra que temos que fazer aqui é analisar o corpo. Por padrão, o API Gateway codifica qualquer JSON passado no corpo. Podemos então desestruturar o texto e a linguagem do corpo.

const body = JSON.parse(event.body);const { text, language } = body;

Agora precisamos verificar se o usuário ignorou o texto e o idioma.

if (!text) {    // retrun 400}if (!language) {    // return 400}

Na última parte, criamos a resposta 400 como uma função no arquivo. Como vamos usar essas respostas de API em vários arquivos, é uma boa ideia puxá-los para seus próprios comum Arquivo.

Crie uma nova pasta em lambdas chamado common. É aqui que vamos armazenar todas as funções comuns.

Nessa pasta, crie um novo arquivo chamado apiResponses.ts. Este arquivo vai exportar o apiResponses objeto com o _200 e _400 métodos nele. Se você precisar retornar outros códigos de resposta, poderá adicioná-los a este objeto.

const apiResponses = {    _200: (body: { [key: string]: any }) => {        return {            statusCode: 200,            body: JSON.stringify(body, null, 2),        };    },    _400: (body: { [key: string]: any }) => {        return {            statusCode: 400,            body: JSON.stringify(body, null, 2),        };    },};export default apiResponses;

Agora podemos importar esse objeto em nosso código e usar esses métodos comuns em nosso código. No topo do nosso translate.ts arquivo, agora podemos adicionar esta linha:

import apiResponses from './common/apiResponses';

e atualizar nossas verificações de texto e idioma para chamar o _400 método nesse objeto:

if (!text) {    return apiResponses._400({ message: 'missing text fom the body' });}if (!language) {    return apiResponses._400({ message: 'missing language from the body' });}

Feito isso, sabemos que temos o texto a ser traduzido e o idioma para o qual traduzir, para que possamos iniciar o processo de tradução.

Usar o aws-sdk é quase sempre uma tarefa assíncrona, então vamos envolvê-la em um tentar / pegar para que nosso tratamento de erros seja mais fácil.

try {    } catch (error) {    }

A primeira coisa que precisamos fazer é importar o aws-sdk e criar uma nova instância do serviço de tradução.

Para fazer isso, precisamos instalar o aws-sdk e importá-lo. Primeira corrida npm install --save aws-sdk e, em seguida, adicione este código ao topo do seu arquivo de tradução:

import * as AWS from 'aws-sdk';const translate = new AWS.Translate();

Com isso podemos começar a escrever nosso código de tradução. Vamos começar com a linha que faz a tradução primeiro. Adicione isso no experimentar seção.

const translatedMessage = await translate.translateText(translateParams).promise();

Uma coisa que alguns de vocês devem ter notado é que estamos passando translateParams sem ter definido ainda. Isso ocorre porque ainda não temos certeza de que tipo é.

Para descobrir isso, podemos usar uma ferramenta no VS Code chamada go to definition. Isso nos permite pular para onde a função foi definida para que possamos descobrir qual é o tipo dos parâmetros. Você pode clicar com o botão direito e selecionar go to definition ou segure Ctrl e clique na função.

Screenshot 2020 08 23 at 08.14.03

Como você pode ver o translateText função leva um parâmetro de Translate.Types.TranslateTextRequest.

Outra maneira de descobrir isso é usar intelisense passando o mouse sobre o translateText função. Você deveria ver isso, onde você pode ver que params: AWS.Translate.TranslateTextRequest:

Screenshot 2020 08 23 at 08.15.30

Com isso, podemos criar nossos parâmetros de tradução acima da solicitação de tradução que fizemos anteriormente. Podemos então preenchê-lo com base no tipo que estamos definindo. Isso garante que estamos passando os campos corretos.

const translateParams: AWS.Translate.Types.TranslateTextRequest = {    Text: text,    SourceLanguageCode: 'en',    TargetLanguageCode: language,};

Agora que temos os parâmetros e os estamos passando para o translate.translateText função, podemos começar a criar nossa resposta. Essa vai ser apenas uma resposta 200 com a mensagem traduzida.

return apiResponses._200({ translatedMessage });

Com tudo isso feito, podemos passar para o pegar seção. Aqui, queremos apenas fazer o logout do erro e, em seguida, retornar uma resposta 400 do arquivo comum.

console.log('error in the translation', error);return apiResponses._400({ message: 'unable to translate the message' });

Com isso concluído, terminamos com nosso código lambda, então precisamos passar para nosso severless.ts para adicionar este novo endpoint de API e dar a ele as permissões necessárias.

No serverless.ts arquivo, podemos rolar para baixo até o functions seção. Aqui, precisamos adicionar uma nova função ao objeto.

translate: {    handler: 'lambdas/translate.handler',    events: [        {            http: {                path: 'translate',                method: 'POST',                cors: true,            },        },    ],},

A principal diferença entre este e o endpoint anterior é que o endpoint agora é um POSTAR método. Isso significa que se você tentar e fazer um OBTER solicitação para este caminho de URL, você obterá uma resposta de erro.

A última coisa a fazer é dar aos lambdas permissão para usar o serviço Translate. Com quase todos os serviços da AWS, você precisará adicionar permissões extras para poder usar o de dentro de um lambda.

Para fazer isso, adicionamos um novo campo ao provider seção chamada iamRoleStatements. Esta é uma série de permitir ou negar declarações para diferentes serviços e recursos.

iamRoleStatements: [    {        Effect: 'Allow',        Action: ['translate:*'],        Resource: '*',    },],

Com isso adicionado, temos tudo o que precisamos configurar para que possamos executar sls deploy para implantar nossa nova API.

Depois de implementado, podemos obter a URL da API e usar uma ferramenta como o carteiro ou postwoman.io para fazer um pedido a esse URL. Só precisamos deixar passar um corpo de:

{    "text": "This is a test message for translation",    "language": "fr"}

e então devemos obter uma resposta 200 de:

{  "translatedMessage": {    "TranslatedText": "Ceci est un message de test pour la traduction",    "SourceLanguageCode": "en",    "TargetLanguageCode": "fr"  }}

Neste artigo, aprendemos como:

  • Configure um novo repositório TypeScript com severless create --template aws-nodejs-typescript
  • Adicione nosso próprio Lambda que retorna uma seleção de dados codificados permanentemente
  • Adicionado aquele Lambda como um endpoint de API
  • Adicionado outro Lambda que irá traduzir automaticamente qualquer texto passado para ele
  • Adicionou um endpoint de API e deu ao Lambda as permissões de que precisava para funcionar

Se você gostou deste artigo e quer saber mais sobre Serverless e AWS, então tenho um canal no Youtube com mais de 50 vídeos sobre tudo isso. Eu recomendo assistir os vídeos que você achar mais interessantes no meu Serverless e lista de reprodução AWS.