Trabalho com o AWS CDK em JavaScript - Kit de desenvolvimento em nuvem da AWS (CDK da AWS) v2

Este é o Guia do desenvolvedor do AWS CDK v2. O CDK v1 antigo entrou em manutenção em 1º de junho de 2022 e encerrou o suporte em 1º de junho de 2023.

Trabalho com o AWS CDK em JavaScript

O JavaScript é uma linguagem de cliente com suporte total no AWS CDK e considerada estável. O trabalho com o kit de desenvolvimento em nuvem da AWS (CDK da AWS) em JavaScript usa ferramentas familiares, incluindo o Node.js e o Node Package Manager (npm). Você também pode usar o Yarn se preferir, embora os exemplos neste Guia usem o NPM. Os módulos que compõem a Biblioteca de Constructos da AWS são distribuídos por meio do repositório NPM, npmjs.org.

É possível usar qualquer editor ou IDE. Muitos desenvolvedores do AWS CDK usam o Visual Studio Code (ou seu equivalente de código aberto, o VSCodium), que tem um bom suporte para JavaScript.

Conceitos básicos do JavaScript

Para trabalhar com o AWS CDK, é necessário ter uma conta e credenciais da AWS e ter instalado o Node.js e o Kit de Ferramentas CDK da AWS. Consulte Conceitos básicos do AWS CDK.

As aplicações do AWS CDK em JavaScript não exigem pré-requisitos adicionais além desses.

nota

Suspensão de uso de linguagem de terceiros: a versão da linguagem só é suportada até seu EOL (End Of Life) compartilhado pelo fornecedor ou pela comunidade e está sujeita a alterações mediante aviso prévio.

Criação de um projeto

Você cria um novo projeto do AWS CDK invocando cdk init em um diretório vazio. Use a opção --language e especifiquejavascript:

$ mkdir my-project $ cd my-project $ cdk init app --language javascript

A criação de um projeto também instala o módulo aws-cdk-lib e suas dependências.

cdk init usa o nome da pasta do projeto para nomear vários elementos do projeto, incluindo classes, subpastas e arquivos. Hifens no nome da pasta são convertidos em sublinhados. No entanto, o nome deve seguir a forma de um identificador de JavaScript; por exemplo, não deve começar com um número nem conter espaços.

Uso de cdk localmente

Na maioria das vezes, este guia pressupõe que você instale o Kit de Ferramentas CDK globalmente (npm install -g aws-cdk), e os exemplos de comandos fornecidos (como cdk synth) seguem essa suposição. Essa abordagem facilita a atualização do Kit de Ferramentas CDK e, como o CDK adota uma abordagem estrita em relação à compatibilidade com versões anteriores, geralmente há pouco risco em sempre usar a versão mais recente.

Algumas equipes preferem especificar todas as dependências em cada projeto, incluindo ferramentas como o Kit de Ferramentas CDK. Essa prática permite que você fixe esses componentes em versões específicas e garanta que todos os desenvolvedores da sua equipe (e do seu ambiente de CI/CD) usem exatamente essas versões. Isso elimina uma possível fonte de mudança, ajudando a tornar as compilações e implantações mais consistentes e reproduzíveis.

O CDK inclui uma dependência para o Kit de Ferramentas CDK nos package.json dos modelos de projeto em JavaScript. Portanto, se você quiser usar essa abordagem, não precisará fazer nenhuma alteração no seu projeto. Tudo o que você precisa fazer é usar comandos ligeiramente diferentes para compilar sua aplicação e emitir comandos cdk.

Operação Usar ferramentas globais Usar ferramentas locais

Inicializar projeto

cdk init --language javascript

npx aws-cdk init --language javascript

Execute o comando do Kit de Ferramentas CDK

cdk …​

npm run cdk …​ ou npx aws-cdk …​

npx aws-cdk executa a versão do Kit de Ferramentas CDK instalada localmente no projeto atual, se houver, retornando à instalação global, se houver. Se não existir uma instalação global, npx baixa uma cópia temporária do Kit de Ferramentas CDK e a executa. É possível especificar uma versão arbitrária do Kit de Ferramentas CDK usando a sintaxe @: npx aws-cdk@1.120 --version imprime 1.120.0.

dica

Configure um alias para que você possa usar o comando cdk com uma instalação local do Kit de Ferramentas CDK.

macOS/Linux
$ alias cdk="npx aws-cdk"
Windows
doskey cdk=npx aws-cdk $*

Gerenciamento de módulos da Biblioteca de Constructos da AWS

Use o Node Package Manager (npm) para instalar e atualizar os módulos da Biblioteca de Constructos da AWS para uso por suas aplicações, bem como por outros pacotes necessários. (É possível usar yarn em vez de npm, se preferir.) npm também instala as dependências desses módulos automaticamente.

A maioria dos constructos da AWS está no pacote principal do CDK, chamado aws-cdk-lib, que é uma dependência padrão em novos projetos criados por cdk init. Os módulos “experimentais” da Biblioteca de Constructos da AWS, nos quais constructos de nível superior ainda estão em desenvolvimento, são nomeados como aws-cdk-lib/<SERVICE-NAME>-alpha. O nome do serviço tem um prefixo aws-. Se você não tiver certeza do nome de um módulo, procure-o no NPM.

nota

A Referência de API do CDK também mostra os nomes dos pacotes.

Por exemplo, o comando abaixo instala o módulo experimental para AWS CodeStar.

npm install @aws-cdk/aws-codestar-alpha

O suporte da Biblioteca de Constructos de alguns serviços está em mais de um namespace. Por exemplo, além de aws-route53, há três namespaces adicionais do Amazon Route 53, aws-route53-targets, aws-route53-patterns e aws-route53resolver.

As dependências do seu projeto são mantidas em package.json. É possível editar esse arquivo para bloquear algumas ou todas as suas dependências em uma versão específica ou para permitir que elas sejam atualizadas para versões mais recentes sob determinados critérios. Para atualizar as dependências do NPM do seu projeto para a versão mais recente permitida de acordo com as regras que você especificou em package.json:

npm update

Em JavaScript, você importa módulos para o seu código com o mesmo nome usado para instalá-los usando o NPM. Recomendamos as práticas a seguir ao importar classes do AWS CDK e módulos da Biblioteca de Constructos da AWS em suas aplicações. Seguir essas diretrizes ajudará a tornar seu código consistente com outras aplicações do AWS CDK, além de ser mais fácil de entender.

  • Use require(), não diretivas import do estilo ES6. Versões mais antigas do Node.js não suportam importações de ES6, portanto, usar a sintaxe mais antiga é mais amplamente compatível. (Se você realmente quiser usar as importações do ES6, use o esm para garantir que seu projeto seja compatível com todas as versões suportadas do Node.js.)

  • Geralmente, importe classes individuais de aws-cdk-lib.

    const { App, Stack } = require('aws-cdk-lib');
  • Se precisar de muitas classes de aws-cdk-lib, você pode usar um alias de namespace de cdk, em vez de importar as classes individuais. Evite fazer as duas coisas.

    const cdk = require('aws-cdk-lib');
  • Geralmente, importe AWS Construct Libraries usando aliases curtos de namespace.

    const { s3 } = require('aws-cdk-lib/aws-s3');

Gerenciamento de dependências em JavaScript

Em projetos do CDK em JavaScript, as dependências são especificadas no arquivo package.json no diretório principal do projeto. Os módulos principais do AWS CDK estão em um único pacote NPM chamado aws-cdk-lib.

Quando você instala um pacote usando npm install, o NPM grava o pacote em package.json para você.

Se preferir, você pode usar o Yarn no lugar do NPM. No entanto, o CDK não oferece suporte ao modo plug-and-play do Yarn, que é o modo padrão no Yarn 2. Adicione o seguinte ao arquivo .yarnrc.yml do seu projeto para desativar esse atributo.

nodeLinker: node-modules

Aplicações do CDK

Veja a seguir um exemplo de arquivo package.json gerado pelo comando cdk init --language typescript. O arquivo gerado para JavaScript é semelhante, só que sem as entradas relacionadas ao TypeScript.

{ "name": "my-package", "version": "0.1.0", "bin": { "my-package": "bin/my-package.js" }, "scripts": { "build": "tsc", "watch": "tsc -w", "test": "jest", "cdk": "cdk" }, "devDependencies": { "@types/jest": "^26.0.10", "@types/node": "10.17.27", "jest": "^26.4.2", "ts-jest": "^26.2.0", "aws-cdk": "2.16.0", "ts-node": "^9.0.0", "typescript": "~3.9.7" }, "dependencies": { "aws-cdk-lib": "2.16.0", "constructs": "^10.0.0", "source-map-support": "^0.5.16" } }

Para aplicações CDK implantáveis, aws-cdk-lib deve ser especificado na seção dependencies de package.json. É possível usar um especificador de número de versão com acento circunflexo (^) para indicar que aceitará versões posteriores à especificada, desde que estejam na mesma versão principal.

Para constructos experimentais, especifique as versões exatas dos módulos da Biblioteca de Constructos alfa, que têm APIs que podem mudar. Não use ^ ou ~, pois versões posteriores desses módulos podem trazer alterações na API que podem prejudicar sua aplicação.

Especifique as versões das bibliotecas e ferramentas necessárias para testar sua aplicação (por exemplo, a estrutura de teste jest) na seção devDependencies de package.json. Opcionalmente, use ^ para especificar que versões compatíveis posteriores sejam aceitáveis.

Bibliotecas de constructos de terceiros

Se você estiver desenvolvendo uma biblioteca de constructos, especifique suas dependências usando uma combinação das seções peerDependencies e devDependencies, conforme mostrado no arquivo package.json de exemplo a seguir.

{ "name": "my-package", "version": "0.0.1", "peerDependencies": { "aws-cdk-lib": "^2.14.0", "@aws-cdk/aws-appsync-alpha": "2.10.0-alpha", "constructs": "^10.0.0" }, "devDependencies": { "aws-cdk-lib": "2.14.0", "@aws-cdk/aws-appsync-alpha": "2.10.0-alpha", "constructs": "10.0.0", "jsii": "^1.50.0", "aws-cdk": "^2.14.0" } }

Em peerDependencies, use um acento circunflexo (^) para especificar a versão mais baixa de aws-cdk-lib com a qual sua biblioteca trabalha. Isso maximiza a compatibilidade da sua biblioteca com uma variedade de versões do CDK. Especifique as versões exatas dos módulos de Biblioteca de Constructos alfa, que têm APIs que podem mudar. O uso de peerDependencies garante que haja apenas uma cópia de todas as bibliotecas CDK na árvore node_modules.

Em devDependencies, especifique as ferramentas e bibliotecas que você precisa para testar, opcionalmente com ^ para indicar que versões compatíveis posteriores são aceitáveis. Especifique exatamente (sem ^ ou ~) as versões mais baixas de aws-cdk-lib e outros pacotes do CDK com os quais você anuncia a compatibilidade da sua biblioteca. Essa prática garante que seus testes sejam executados nessas versões. Dessa forma, se você usar inadvertidamente um atributo encontrado apenas em versões mais recentes, seus testes poderão detectá-lo.

Atenção

peerDependencies são instalados automaticamente somente pelo NPM 7 e versões posteriores. Se você estiver usando o NPM 6 ou versão anterior, ou se estiver usando o Yarn, deverá incluir as dependências de suas dependências no devDependencies. Caso contrário, elas não serão instaladas e você receberá um aviso sobre dependências de pares não resolvidas.

Instalação e atualização de dependências

Use o comando a seguir para instalar as dependências do seu projeto.

NPM
# Install the latest version of everything that matches the ranges in 'package.json' npm install # Install the same exact dependency versions as recorded in 'package-lock.json' npm ci
Yarn
# Install the latest version of everything that matches the ranges in 'package.json' yarn upgrade # Install the same exact dependency versions as recorded in 'yarn.lock' yarn install --frozen-lockfile

Para atualizar os módulos instalados, os comandos npm install e yarn upgrade anteriores podem ser usados. Qualquer um dos comandos atualiza os pacotes em node_modules para as versões mais recentes que atendem às regras em package.json. No entanto, não atualizam package.json por conta própria, o que talvez você queira fazer para definir uma nova versão mínima. Se você hospedar seu pacote no GitHub, poderá configurar as atualizações de versão do Dependabot para atualizar package.json automaticamente. Como alternativa, use npm-check-updates.

Importante

Por padrão, quando você instala ou atualiza dependências, o NPM e o Yarn escolhem a versão mais recente de cada pacote que atenda aos requisitos especificados em package.json. Sempre existe o risco de que essas versões sejam quebradas (acidental ou intencionalmente). Teste minuciosamente depois de atualizar as dependências do seu projeto.

Expressões idiomáticas do AWS em JavaScript

Props

Todas as classes da Biblioteca de Constructos da AWS são instanciadas usando três argumentos: o escopo no qual o constructo está sendo definido (seu pai na árvore de constructos), um id e props, um pacote de pares de chave/valor que o constructo usa para configurar os recursos da AWS que cria. Outras classes e métodos também usam o padrão “pacote de atributos” para argumentos.

Usar um IDE ou editor que tenha um bom preenchimento automático de JavaScript ajudará a evitar erros ortográficos nos nomes das propriedades. Se um constructo espera uma propriedade encryptionKeys e você a escreve encryptionkeys ao instanciá-lo, o valor que pretendia passar não foi transmitido. Isso pode causar um erro no momento da síntese, se a propriedade for necessária, ou fazer com que a propriedade seja ignorada silenciosamente se for opcional. No último caso, você pode obter um comportamento padrão que pretendia substituir. Tome cuidado especial aqui.

Ao criar uma subclasse de uma classe da Biblioteca de Constructos da AWS (ou substituir um método que usa um argumento semelhante a adereços), talvez você queira aceitar propriedades adicionais para seu próprio uso. Esses valores serão ignorados pela classe principal ou pelo método substituído, porque eles nunca são acessados nesse código, então você geralmente pode transmitir todas as props recebidas.

Uma versão futura do AWS CDK poderia coincidentemente adicionar uma nova propriedade com um nome que você usou para sua própria propriedade. Passar o valor que você recebe para a cadeia de herança pode causar um comportamento inesperado. É mais seguro passar uma cópia rasa dos adereços que você recebeu com sua propriedade removida ou configurada para undefined. Por exemplo:

super(scope, name, {...props, encryptionKeys: undefined});

Como alternativa, nomeie suas propriedades para que fique claro que elas pertencem ao seu constructo. Dessa forma, é improvável que colidam com propriedades em versões futuras do AWS CDK. Se houver muitas delas, use um único objeto com nome apropriado para mantê-las.

Valores ausentes

Valores ausentes em um objeto (como props) têm o valor undefined em JavaScript. As técnicas usuais se aplicam para lidar com eles. Por exemplo, uma expressão idiomática comum para acessar uma propriedade de um valor que pode ser indefinido é a seguinte:

// a may be undefined, but if it is not, it may have an attribute b // c is undefined if a is undefined, OR if a doesn't have an attribute b let c = a && a.b;

No entanto, se a pudesse ter algum outro valor “falso” além de undefined, é melhor tornar o teste mais explícito. Aqui, aproveitaremos o fato de que null e undefined são iguais para testar os dois ao mesmo tempo:

let c = a == null ? a : a.b;
dica

Node.js 14.0 e versões posteriores oferecem suporte a novos operadores que podem simplificar o tratamento de valores indefinidos. Para obter mais informações, consulte as propostas opcionais de encadeamento e coalescência nula.

Uso de exemplos de TypeScript com JavaScript

O TypeScript é a linguagem que usamos para desenvolver o AWS CDK e foi a primeira linguagem com suporte para o desenvolvimento de aplicações. Portanto, muitos exemplos de código disponíveis do AWS CDK são escritos em TypeScript. Esses exemplos de código podem ser um bom recurso para desenvolvedores de JavaScript; você só precisa remover as partes específicas do código TypeScript.

Os trechos do TypeScript geralmente usam as palavras-chave import e export mais recentes do ECMAScript para importar objetos de outros módulos e declarar que os objetos serão disponibilizados fora do módulo atual. Node.js acaba de começar a oferecer suporte a essas palavras-chave em suas versões mais recentes. Dependendo da versão do Node.js que você está usando (ou deseja oferecer suporte), é possível reescrever as importações e exportações para usar a sintaxe mais antiga.

As importações podem ser substituídas por chamadas para a função require().

TypeScript
import * as cdk from 'aws-cdk-lib'; import { Bucket, BucketPolicy } from 'aws-cdk-lib/aws-s3';
JavaScript
const cdk = require('aws-cdk-lib'); const { Bucket, BucketPolicy } = require('aws-cdk-lib/aws-s3');

As exportações podem ser atribuídas ao objeto module.exports.

TypeScript
export class Stack1 extends cdk.Stack { // ... } export class Stack2 extends cdk.Stack { // ... }
JavaScript
class Stack1 extends cdk.Stack { // ... } class Stack2 extends cdk.Stack { // ... } module.exports = { Stack1, Stack2 }
nota

Uma alternativa para usar as importações e exportações de estilo antigo é usar o módulo esm.

Depois de classificar as importações e exportações, é possível se aprofundar no código real. É possível se deparar com esses atributos comumente usados do TypeScript:

  • Anotações de tipo

  • Definições de interface

  • Conversões de tipo/transmissões

  • Modificadores de acesso

As anotações de tipo podem ser fornecidas para variáveis, membros da classe, parâmetros da função e tipos de retorno da função. Para variáveis, parâmetros e membros, os tipos são especificados seguindo o identificador com dois pontos e o tipo. Os valores de retorno da função seguem a assinatura da função e consistem em dois pontos e no tipo.

Para converter código com anotação de tipo em JavaScript, remova os dois pontos e o tipo. Os membros da classe devem ter algum valor em JavaScript; defina-os como undefined se eles tiverem apenas uma anotação de tipo em TypeScript.

TypeScript
var encrypted: boolean = true; class myStack extends cdk.Stack { bucket: s3.Bucket; // ... } function makeEnv(account: string, region: string) : object { // ... }
JavaScript
var encrypted = true; class myStack extends cdk.Stack { bucket = undefined; // ... } function makeEnv(account, region) { // ... }

No TypeScript, as interfaces são usadas para dar um nome aos pacotes de propriedades obrigatórias e opcionais e seus tipos. Em seguida, você pode usar o nome da interface como uma anotação de tipo. O TypeScript garantirá que o objeto usado como, por exemplo, argumento para uma função tenha as propriedades necessárias dos tipos corretos.

interface myFuncProps { code: lambda.Code, handler?: string }

O JavaScript não tem um atributo de interface, de forma que, depois de remover as anotações de tipo, exclua totalmente as declarações da interface.

Quando uma função ou método retorna um tipo de uso geral (como object), mas você deseja tratar esse valor como um tipo filho mais específico para acessar propriedades ou métodos que não fazem parte da interface do tipo mais geral, o TypeScript permite converter o valor usando as seguido por um nome de tipo ou interface. O JavaScript não oferece suporte a isso (e não precisa), então simplesmente remova as e o identificador a seguir. Uma sintaxe de conversão menos comum é usar um nome de tipo entre colchetes, <LikeThis>; essas conversões também devem ser removidas.

Por fim, o TypeScript suporta os modificadores de acesso public, protected e private para membros de classes. Todos os membros de classe em JavaScript são públicos. Basta remover esses modificadores onde quer que você os veja.

Saber como identificar e remover esses atributos do TypeScript ajuda muito na adaptação de trechos curtos do TypeScript ao JavaScript. Porém, pode ser impraticável converter exemplos mais longos do TypeScript dessa forma, pois é mais provável que eles usem outros atributos do TypeScript. Para essas situações, recomendamos o Sucrase. O Sucrase não reclamará se o código usar uma variável indefinida, por exemplo, como tsc faria. Se for sintaticamente válido, com poucas exceções, o Sucrase pode traduzi-lo para JavaScript. Isso o torna particularmente valioso para converter trechos que podem não ser executáveis isoladamente.

Migração para TypeScript

Muitos desenvolvedores de JavaScript migram para o TypeScript à medida que seus projetos se tornam maiores e mais complexos. O TypeScript é um superconjunto de JavaScript. Todo código em JavaScript é código em TypeScript válido, portanto, e nenhuma alteração em seu código é necessária, também sendo uma linguagem com suporte no AWS. As anotações de tipo e outros atributos do TypeScript são opcionais e podem ser adicionados à sua aplicação do AWS CDK à medida que você achar valor neles. O TypeScript também oferece acesso antecipado a novos atributos de JavaScript, como encadeamento opcional e coalescência nula, antes de serem finalizados, e sem a necessidade de atualizar o Node.js.

As interfaces “baseadas em formas” do TypeScript, que definem pacotes de propriedades obrigatórias e opcionais (e seus tipos) em um objeto, permitem que erros comuns sejam detectados enquanto você escreve o código e facilitam que seu IDE forneça preenchimento automático robusto e outros conselhos de codificação em tempo real.

A codificação em TypeScript envolve uma etapa adicional: compilar sua aplicação com o compilador TypeScript, tsc. Para aplicações típicas do AWS CDK, a compilação requer alguns segundos no máximo.

A maneira mais fácil de migrar uma aplicação existente do AWS CDK em JavaScript para o TypeScript é criar um novo projeto em TypeScript usando cdk init app --language typescript e, em seguida, copiar seus arquivos de origem (e quaisquer outros arquivos necessários, como ativos como o código-fonte da função do AWS Lambda) para o novo projeto. Renomeie seus arquivos JavaScript para finalizar .ts e começar a desenvolver em TypeScript.