O AWS AppSync é um serverless GraphQL backend-as-a-service. A maioria dos artigos online mostra seu uso através do console da AWS e configurando via interface web, o que não é uma abordagem centrada em código. Eu gostaria de mostrar uma abordagem orientada a código, empregando uma técnica chamada Infraestrutura como Código usando o AWS CloudFormation. O CloudFormation permite que você especifique todos os recursos da AWS na forma de código e automatize suas implantações por meio da linha de comando. Desta forma, todos os recursos de infraestrutura necessários para o seu aplicativo se tornam parte do repositório git - controlados por versão. Você pode reproduzir a stack inteira (conjunto de recursos relacionados) na nuvem com um único comando, ao invés de repetir as etapas manualmente por meio da GUI. Depois que a stack inicial é criada, você pode implantar facilmente alterações em sua infraestrutura, modificando o arquivo de modelo e, em seguida, executando comandos por meio da linha de comando. Essa abordagem oferece controle total direto por meio de código e é muito flexível para se integrar ao restante do ecossistema da AWS.
Mostrarei passo a passo como criar e implantar uma API AppSync GraphQL de nível de produção usando o DynamoDB, tudo a partir do conforto de seu editor e terminal.
1. Definindo o esquema GraphQL
Iremos criar um esquema de exemplo com uma consulta para obter contatos e uma mutação para adicionar um novo contato e salvar o arquivo como schema.graphql no diretório principal do projeto.
mkidr exemplo-appsync
cd exemplo-appsync
touch schema.graphql
vim schema.graphql
Adicionamos:
type Contact {
username: String!
fullName: String!
email: String!
phone: String
}
input ContactInput {
fullName: String!
email: String!
phone: String
}
type Query {
getContacts: [Contact!]!
}
type Mutation {
addContact(username: String! contact: ContactInput!): Contact
}
type Schema {
query: Query
mutation: Mutation
}
2. Adicionar modelos de mapeamento para os Resolvers
O modelo de mapeamento de resolução informa ao AppSync como converter uma solicitação de GraphQL recebida em instruções para sua fonte de dados do back-end e como traduzir a resposta dessa origem de dados de volta para uma resposta do GraphQL. Criaremos modelos de mapeamento de solicitação e resposta separados em arquivos diferentes para cada resolver.
$ mkdir mapping-templates
$ cd mapping-templates
$ touch addContact.request.vm
$ touch addContact.response.vm
$ touch getContacts.request.vm
$ touch getContacts.response.vm
Em addContact.request.vm
, adicione:
## mapeamento de resolução da requisição da mutação `addContact`, mapeando para a operação `PutItem` do DynamoDB.
{
"version": "2017-02-28",
"operation": "PutItem",
"key": {
"username": $util.dynamodb.toDynamoDBJson($ctx.args.username)
},
"attributeValues": $util.dynamodb.toMapValuesJson($ctx.args.contact)
}
Em addContact.response.vm
, adicione:
## mapeamento de resolução da resposta da mutação `addContact`, retornando o novo objeto de contato adicionado.
$util.toJson($ctx.result)
Em getContacts.request.vm
, adicione:
## mapeamento de resolução da requisição da query `getContacts`, mapeando para a operação `Scan` do DynamoDB.
{
"version": "2017-02-28",
"operation": "Scan"
}
Em getContacts.response.vm
, adicione:
## mapeamento de resolução da resposta da query `getContacts`, retornando todos os contatos.
$util.toJson($ctx.result.items)
3. Especifique recursos no modelo do CloudFormation
Aqui criaremos o modelo CloudFormation no formato YAML, que é mais legível do que sua contraparte JSON. Ele especifica detalhes sobre nossa AppSync API, API Key, o esquema GraphQL, a tabela do DynamoDB, nossas Fontes de Dados para a API AppSync, os Resolvers do GraphQL e o acesso à Tabela do DynamoDB usando uma IAM Role.
$ touch template.yml
$ vim template.yml
E em seguida:
AWSTemplateFormatVersion: '2010-09-09'
Description: Create AppSync GraphQL API using DynamoDB
Parameters:
ApiName:
Type: String
Description: Name of the API - used to generate unique names for resources
MinLength: 3
MaxLength: 25
AllowedPattern: '^[a-zA-Z][a-zA-Z0-9\-]*$'
Resources:
GraphQLApi:
Type: AWS::AppSync::GraphQLApi
Properties:
Name: !Sub ${ApiName}-graphql-api
AuthenticationType: API_KEY
ApiKey:
Type: AWS::AppSync::ApiKey
Properties:
ApiId: !GetAtt GraphQLApi.ApiId
GraphQLSchema:
Type: AWS::AppSync::GraphQLSchema
Properties:
ApiId: !GetAtt GraphQLApi.ApiId
# caminho para o esquema graphql
DefinitionS3Location: schema.graphql
ContactsTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: !Sub ${ApiName}-contacts
KeySchema:
- AttributeName: username
KeyType: HASH
AttributeDefinitions:
- AttributeName: username
AttributeType: S
BillingMode: PAY_PER_REQUEST
ApiRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- appsync.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName: !Sub ${ApiName}-dynamo-access
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:DeleteItem
- dynamodb:UpdateItem
- dynamodb:Query
- dynamodb:Scan
- dynamodb:BatchGetItem
- dynamodb:BatchWriteItem
Resource: !GetAtt ContactsTable.Arn
ContactsTableDataSource:
Type: AWS::AppSync::DataSource
Properties:
Name: ContactsTableDataSource
Type: AMAZON_DYNAMODB
ServiceRoleArn: !GetAtt ApiRole.Arn
DynamoDBConfig:
AwsRegion: !Ref AWS::Region
TableName: !Ref ContactsTable
ApiId: !GetAtt GraphQLApi.ApiId
QueryGetContactsResolver:
Type: AWS::AppSync::Resolver
Properties:
TypeName: Query
FieldName: getContacts
DataSourceName: !GetAtt ContactsTableDataSource.Name
# caminho para o arquivo de mapeamento de resolução da requisição
RequestMappingTemplateS3Location: mapping-templates/getContacts.request.vm
# caminho para o arquivo de mapeamento de resolução da resposta
ResponseMappingTemplateS3Location: mapping-templates/getContacts.response.vm
ApiId: !GetAtt GraphQLApi.ApiId
MutationAddContactResolver:
Type: AWS::AppSync::Resolver
Properties:
TypeName: Mutation
FieldName: addContact
DataSourceName: !GetAtt ContactsTableDataSource.Name
# caminho para o arquivo de mapeamento de resolução da requisição
RequestMappingTemplateS3Location: mapping-templates/addContact.request.vm
# caminho para o arquivo de mapeamento de resolução da resposta
ResponseMappingTemplateS3Location: mapping-templates/addContact.response.vm
ApiId: !GetAtt GraphQLApi.ApiId
Outputs:
GraphQLApiEndpoint:
Description: GraphQL API URL
Value: !GetAtt GraphQLApi.GraphQLUrl
ApiKey:
Description: API Key
Value: !GetAtt ApiKey.ApiKey
4. Deploy usando o AWS CLI
Primeiro, instale o AWS CLI e configure-o especificando as credenciais de segurança e as informações de região da sua conta. Forneça a opção de perfil em todos os comandos se você quiser usar uma configuração de perfil específica, caso contrário, usará o perfil padrão.
Crie um bucket do S3 para fazer o upload de arquivos de código:
aws s3 mb s3://contacts-dev-codes --profile faisal
Execute o comando package para empacotar os artefatos locais referenciados no arquivo CloudFormation que criamos, template.yml, para o bucket S3 especificado. Isso gerará um novo arquivo, que se irá usar referências aos arquivos no bucket S3 ao invés dos arquivos locais.
aws cloudformation package \
--s3-bucket contacts-dev-codes \
--template-file template.yml \
--output-template-file packaged-template.yml \
--profile faisal
Execute o comando deploy utilizando o arquivo recém-gerado para criar todos os recursos de infraestrutura. Além disso, não esqueça de fornecer o nome da stack e os parâmetros necessários do template:
aws cloudformation deploy \
--stack-name contacts-dev \
--template-file packaged-template.yml \
--capabilities CAPABILITY_IAM \
--parameter-overrides ApiName=contacts-dev \
--profile faisal
Agora você tem uma API AppSync GraphQL totalmente funcional com DynamoDB na AWS. Você pode usar os comandos package e deploy repetidamente sempre que fizer alterações no template, ele criará automaticamente o conjunto de mudanças e o executará. Se você estiver usando o Node.js, poderá adicionar esses comandos como scripts do NPM ao package.json de um projeto, por conveniência.
Eu criei o repositório GitHub que contém todo o código padrão com a configuração completa necessária para o kickstart do projeto AppSync.
Crédito
- AWS AppSync code-centric development using CloudFormation, escrito originalmente por Faisal Hasnain
Top comments (4)
Tenho usado o AWS Amplify que automatiza bastante coisa no CloudFormation, mas interessante saber como funciona debaixo dos panos.
Exemplo legal usando Amplify que postaram dias atrás:
aws.amazon.com/blogs/mobile/amplif...
Parabéns por sempre compartilhar conteúdo de qualidade com a comunidade BR.
obrigado pelo comentário Helder!
ao longo do tempo eu aprendi a gosta do CloudFormation. A documentação não é das melhores, mas tem muito conteúdo da AWS sobre, que ajuda bastante.
eu to para escrever um tutorial de como escrever um projeto AppSync com CloudFormation Stacks, que seria um modo prático de modularizar o projeto para produção e utilizar Output->Input entre stacks.
faz mais de meses que tá parado, por falta de tempo mesmo hahaha,
mas depois que você pega a prática e monta alguns templates, fica muito fácil usar CloudFormation puro.
aqui onde trabalho usamos cfn para tudo no lado da infra e apis, apenas client-side apps usam alguma abstração, tais como serverless framework, sam, amplify etc.
alguns plugins que sempre vejo por aqui:
Hmm English version?
follow the link in the last section "Crédito", the title is in en