As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.
Usando o Aurora Serverless v2 com AWS AppSync
Conecte sua API GraphQL aos bancos de dados Aurora Serverless usando o. AWS AppSync Essa integração permite a você executar instruções SQL por meio de consultas, mutações e assinaturas do GraphQL, oferecendo uma maneira flexível de interagir com os dados relacionais.
nota
Este tutorial usa a Região US-EAST-1.
Benefícios
Integração perfeita entre GraphQL e bancos de dados relacionais
Capacidade de realizar operações SQL por meio de interfaces GraphQL
Escalabilidade da tecnologia sem servidor com Aurora Serverless v2
Acesso seguro aos dados por meio do AWS Secrets Manager
Proteção contra injeção de SQL por meio da limpeza de entradas
Recursos de consulta flexíveis, inclusive operações de filtragem e alcance
Casos de uso comuns
Criação de aplicações escaláveis com requisitos de dados relacionais
Para criar APIs isso, é necessária a flexibilidade do GraphQL e os recursos do banco de dados SQL.
Gerenciamento das operações de dados por meio de mutações e consultas do GraphQL
Implementação dos padrões de acesso seguro ao banco de dados
Neste tutorial, você aprenderá os itens a seguir.
Configurar o cluster do Aurora Serverless v2
Habilitar a funcionalidade da API Data
Criar e configurar estruturas do banco de dados
Definir esquemas do GraphQL para operações do banco de dados
Implementar resolvedores para consultas e mutações
Proteger o acesso a dados por meio da limpeza de entradas indicada
Executar operações de banco de dados variadas por meio de interfaces GraphQL
Tópicos
Configuração do cluster do banco de dados
Antes de adicionar uma fonte de dados do Amazon RDS AWS AppSync, você deve primeiro habilitar uma API de dados em um cluster Aurora Serverless v2 e configurar um segredo usando. AWS Secrets Manager Você pode criar um cluster do Aurora Serverless v2 usando Aurora AWS CLI:
aws rds create-db-cluster \ --db-cluster-identifier appsync-tutorial \ --engine aurora-mysql \ --engine-version 8.0 \ --serverless-v2-scaling-configuration MinCapacity=0,MaxCapacity=1 \ --master-username USERNAME \ --master-user-password COMPLEX_PASSWORD \ --enable-http-endpoint
Isso retornará um ARN para o cluster.
Depois de criar o cluster, você deverá adicionar uma instância do Aurora Serverless v2 usando o comando a seguir.
aws rds create-db-instance \ --db-cluster-identifier appsync-tutorial \ --db-instance-identifier appsync-tutorial-instance-1 \ --db-instance-class db.serverless \ --engine aurora-mysql
nota
Estes endpoints levam tempo para serem ativados. Você pode consultar o status no console do Amazon RDS na guia Conectividade e segurança do cluster. Você também pode verificar o status do seu cluster com o AWS CLI comando a seguir.
aws rds describe-db-clusters \ --db-cluster-identifier appsync-tutorial \ --query "DBClusters[0].Status"
Você pode criar um segredo usando o AWS Secrets Manager console ou AWS CLI
com um arquivo de entrada, como o seguinte, usando o USERNAME e COMPLEX_PASSWORD da etapa anterior.
{ "username": "USERNAME", "password": "COMPLEX_PASSWORD" }
Passe isso como um parâmetro para AWS CLI:
aws secretsmanager create-secret --name HttpRDSSecret --secret-string file://creds.json --region us-east-1
Isso retornará um ARN para o segredo.
Anote o ARN do seu cluster Aurora Serverless e Secret para uso posterior no AppSync console ao criar uma fonte de dados.
Ativar API de dados
Você pode ativar a API de dados em seu cluster seguindo as instruções na documentação do RDS. A API de dados deve ser ativada antes de ser adicionada como fonte de AppSync dados.
Criar banco de dados e tabela
Depois de ativar sua API de dados, você pode garantir que ela funcione com o comando aws
rds-data execute-statement na AWS CLI. Isso garantirá que seu cluster Aurora Serverless seja configurado corretamente antes de adicioná-lo à sua API. AppSync Primeiro crie um banco de dados chamado TESTDB com o parâmetro --sql da seguinte forma:
aws rds-data execute-statement --resource-arn "arn:aws:rds:us-east-1:123456789000:cluster:http-endpoint-test" \ --schema "mysql" --secret-arn "arn:aws:secretsmanager:us-east-1:123456789000:secret:testHttp2-AmNvc1" \ --region us-east-1 --sql "create DATABASE TESTDB"
Se isso for executado sem erro, inclua uma tabela com o comando create table:
aws rds-data execute-statement --resource-arn "arn:aws:rds:us-east-1:123456789000:cluster:http-endpoint-test" \ --schema "mysql" --secret-arn "arn:aws:secretsmanager:us-east-1:123456789000:secret:testHttp2-AmNvc1" \ --region us-east-1 \ --sql "create table Pets(id varchar(200), type varchar(200), price float)" --database "TESTDB"
Se tudo tiver sido executado sem problemas, você poderá adicionar o cluster como fonte de dados na sua AppSync API.
Esquema do GraphQL
Agora que sua API de dados do Aurora Serverless está funcionando com uma tabela, criaremos um esquema do GraphQL e anexaremos resolvedores para executar mutações e assinaturas. Crie uma nova API no AWS AppSync console, navegue até a página Esquema e insira o seguinte:
type Mutation { createPet(input: CreatePetInput!): Pet updatePet(input: UpdatePetInput!): Pet deletePet(input: DeletePetInput!): Pet } input CreatePetInput { type: PetType price: Float! } input UpdatePetInput { id: ID! type: PetType price: Float! } input DeletePetInput { id: ID! } type Pet { id: ID! type: PetType price: Float } enum PetType { dog cat fish bird gecko } type Query { getPet(id: ID!): Pet listPets: [Pet] listPetsByPriceRange(min: Float, max: Float): [Pet] } schema { query: Query mutation: Mutation }
Salve seu esquema e navegue até a página Fontes de dados e crie uma nova fonte de dados. Selecione Banco de dados relacional para o tipo de fonte de dados e forneça um nome amigável. Use o nome do banco de dados que você criou na última etapa, bem como o ARN do cluster em que você o criou. Para a função, você pode AppSync criar uma nova função ou criar uma com uma política semelhante à abaixo:
Observe que há duas instruções nesta política que você está concedendo acesso à função. O primeiro recurso é seu cluster Aurora Serverless e o segundo é seu ARN. AWS Secrets Manager Você precisará fornecer AMBOS ARNs na configuração da fonte de AppSync dados antes de clicar em Criar.
Passe isso como um parâmetro para AWS CLI o.
aws secretsmanager create-secret \ --name HttpRDSSecret \ --secret-string file://creds.json \ --region us-east-1
Isso retornará um ARN para o segredo. Anote o ARN do seu cluster Aurora Serverless e do Secret para mais tarde ao criar uma fonte de dados no console. AWS AppSync
Criar a estrutura do banco de dados
Depois de ativar sua API de dados, você pode garantir que ela funcione com o comando aws
rds-data execute-statement na AWS CLI. Isso garantirá que seu cluster Aurora Serverless v2 seja configurado corretamente antes de adicioná-lo à sua API. AWS AppSync Primeiro, crie um banco de dados chamado TESTDB com o parâmetro --sql da maneira a seguir.
aws rds-data execute-statement \ --resource-arn "arn:aws:rds:us-east-1:111122223333:cluster:appsync-tutorial" \ --secret-arn "arn:aws:secretsmanager:us-east-1:111122223333:secret:appsync-tutorial-rds-secret" \ --region us-east-1 \ --sql "create DATABASE TESTDB"
Se isso for executado sem erros, adicione uma tabela com o comando create table.
aws rds-data execute-statement \ --resource-arn "arn:aws:rds:us-east-1:111122223333:cluster:http-endpoint-test" \ --secret-arn "arn:aws:secretsmanager:us-east-1:111122223333:secret:testHttp2-AmNvc1" \ --region us-east-1 \ --sql "create table Pets(id varchar(200), type varchar(200), price float)" \ --database "TESTDB"
Projetar a interface da API
Depois que a API Data do Aurora Serverless v2 estiver funcionando com uma tabela, criaremos um esquema do GraphQL e anexaremos resolvedores para realizar mutações e assinaturas. Crie uma nova API no AWS AppSync console, navegue até a página Esquema no console e insira o seguinte.
type Mutation { createPet(input: CreatePetInput!): Pet updatePet(input: UpdatePetInput!): Pet deletePet(input: DeletePetInput!): Pet } input CreatePetInput { type: PetType price: Float! } input UpdatePetInput { id: ID! type: PetType price: Float! } input DeletePetInput { id: ID! } type Pet { id: ID! type: PetType price: Float } enum PetType { dog cat fish bird gecko } type Query { getPet(id: ID!): Pet listPets: [Pet] listPetsByPriceRange(min: Float, max: Float): [Pet] } schema { query: Query mutation: Mutation }
Salve seu esquema e navegue até a página Fontes de dados e crie uma nova fonte de dados. Escolha Banco de dados relacional para o tipo Fonte de dados e dê um nome amigável. Use o nome do banco de dados que você criou na última etapa, bem como o ARN do cluster em que você o criou. Para a função, você pode AWS AppSync criar uma nova função ou criar uma com uma política semelhante à seguinte.
Observe que há duas instruções nesta política que você está concedendo acesso à função. O primeiro recurso é seu cluster Aurora Serverless v2 e o segundo é seu ARN. AWS Secrets Manager Você precisará fornecer AMBOS ARNs na configuração da fonte de AWS AppSync dados antes de clicar em Criar.
Conectar a API às operações do banco de dados
Agora que temos um esquema do GraphQL válido e uma fonte de dados RDS, você pode anexar resolvedores aos campos do GraphQL ao esquema. Nossa API oferecerá os seguintes recursos:
-
criar um animal de estimação usando o campo Mutation.createPet
-
atualizar um animal de estimação usando o campo Mutation.updatePet
-
excluir um animal de estimação usando o campo Mutation.deletePet
-
obter um único animal de estimação usando o campo Query.getPet
-
listar tudo usando o campo Query.listPets
-
liste animais de estimação em uma faixa de preço usando o Query. listPetsByPriceRangecampo
Mutation.createPet
No editor de esquemas no AWS AppSync console, no lado direito, escolha Attach Resolver forcreatePet(input:
CreatePetInput!): Pet. Escolha a fonte de dados do RDS. Na seção modelo de mapeamento de solicitação, adicione o seguinte modelo:
#set($id=$utils.autoId()) { "version": "2018-05-29", "statements": [ "insert into Pets VALUES (:ID, :TYPE, :PRICE)", "select * from Pets WHERE id = :ID" ], "variableMap": { ":ID": "$ctx.args.input.id", ":TYPE": $util.toJson($ctx.args.input.type), ":PRICE": $util.toJson($ctx.args.input.price) } }
O sistema executa instruções SQL sequencialmente, com base na ordem na matriz de instruções. Os resultados retornarão na mesma ordem. Como essa é uma mutação, executaremos uma instrução select depois de insert para recuperar os valores confirmados a fim de preencher o modelo de mapeamento de respostas do GraphQL.
Na seção modelo de mapeamento de resposta, adicione o seguinte modelo:
$utils.toJson($utils.rds.toJsonObject($ctx.result)[1][0])
Como as instruções têm duas consultas SQL, precisamos especificar o segundo resultado na matriz que retorna do banco de dados com: $utils.rds.toJsonString($ctx.result))[1][0]).
Mutation.updatePet
No editor de esquemas no AWS AppSync console, escolha Anexar resolvedor paraupdatePet(input: UpdatePetInput!):
Pet. Escolha a fonte de dados do RDS. Na seção Modelo de mapeamento de solicitações, adicione o modelo a seguir.
{ "version": "2018-05-29", "statements": [ $util.toJson("update Pets set type=:TYPE, price=:PRICE WHERE id=:ID"), $util.toJson("select * from Pets WHERE id = :ID") ], "variableMap": { ":ID": "$ctx.args.input.id", ":TYPE": $util.toJson($ctx.args.input.type), ":PRICE": $util.toJson($ctx.args.input.price) } }
Na seção Modelo de mapeamento de respostas, adicione o modelo a seguir.
$utils.toJson($utils.rds.toJsonObject($ctx.result)[1][0])
Mutation.deletePet
No editor de esquemas no AWS AppSync console, escolha Anexar resolvedor paradeletePet(input: DeletePetInput!):
Pet. Escolha a fonte de dados do RDS. Na seção Modelo de mapeamento de solicitações, adicione o modelo a seguir.
{ "version": "2018-05-29", "statements": [ $util.toJson("select * from Pets WHERE id=:ID"), $util.toJson("delete from Pets WHERE id=:ID") ], "variableMap": { ":ID": "$ctx.args.input.id" } }
Na seção Modelo de mapeamento de respostas, adicione o modelo a seguir.
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0][0])
Query.getPet
Agora que as mutações estão criadas para o esquema, conectamos as três consultas para demonstrar como obter itens individuais, listas e aplicar a filtragem SQL. No editor de esquemas no AWS AppSync console, escolha Anexar resolvedor paragetPet(id:
ID!): Pet. Escolha a fonte de dados do RDS. Na seção Modelo de mapeamento de solicitações, adicione o modelo a seguir.
{ "version": "2018-05-29", "statements": [ $util.toJson("select * from Pets WHERE id=:ID") ], "variableMap": { ":ID": "$ctx.args.id" } }
Na seção modelo de mapeamento de resposta, adicione o seguinte modelo:
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0][0])
Query.listPets
No editor de esquemas no AWS AppSync console, no lado direito, escolha Attach Resolver forgetPet(id: ID!):
Pet. Escolha a fonte de dados do RDS. Na seção Modelo de mapeamento de solicitações, adicione o modelo a seguir.
{ "version": "2018-05-29", "statements": [ "select * from Pets" ] }
Na seção Modelo de mapeamento de respostas, adicione o modelo a seguir.
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])
Consulta. listPetsByPriceRange
No editor de esquemas no AWS AppSync console, no lado direito, escolha Attach Resolver forgetPet(id: ID!):
Pet. Escolha a fonte de dados do RDS. Na seção Modelo de mapeamento de solicitações, adicione o modelo a seguir.
{ "version": "2018-05-29", "statements": [ "select * from Pets where price > :MIN and price < :MAX" ], "variableMap": { ":MAX": $util.toJson($ctx.args.max), ":MIN": $util.toJson($ctx.args.min) } }
Na seção modelo de mapeamento de resposta, adicione o seguinte modelo:
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])
Modificar os dados por meio da API
Agora que você configurou todos os seus resolvedores com instruções SQL e conectou a API do GraphQL à API de dados do Aurora Serverless, é possível começar a realizar mutações e consultas. No AWS AppSync console, escolha a guia Consultas e digite o seguinte para criar um animal de estimação:
mutation add { createPet(input : { type:fish, price:10.0 }){ id type price } }
A resposta deve conter o id, o tipo e o preço da seguinte forma:
{ "data": { "createPet": { "id": "c6fedbbe-57ad-4da3-860a-ffe8d039882a", "type": "fish", "price": "10.0" } } }
Você pode modificar este item executando a mutação updatePet:
mutation update { updatePet(input : { id: ID_PLACEHOLDER, type:bird, price:50.0 }){ id type price } }
Observe que usamos o id que foi retornado da operação createPet anteriormente. Esse será um valor único para o seu registro, já que o resolvedor utilizou $util.autoId(). Você pode excluir um registro de maneira semelhante:
mutation delete { deletePet(input : {id:ID_PLACEHOLDER}){ id type price } }
Crie alguns registros com a primeira mutação com valores diferentes para preço e execute algumas consultas.
Recuperar os dados
Ainda na guia Consultas do console, use a instrução a seguir para listar todos os registros criados por você.
query allpets { listPets { id type price } }
Aproveite o predicado SQL WHERE que estava where price > :MIN and price <
:MAX em nosso modelo de mapeamento para o Query. listPetsByPriceRangecom a seguinte consulta do GraphQL:
query petsByPriceRange { listPetsByPriceRange(min:1, max:11) { id type price } }
Você só deve ver registros com um preço acima de US$ 1 ou abaixo de US$ 10. Por fim, é possível realizar consultas para recuperar registros individuais da seguinte maneira:
query onePet { getPet(id:ID_PLACEHOLDER){ id type price } }
Proteger o acesso a dados
A injeção de SQL é uma vulnerabilidade de segurança em aplicações de banco de dados. Isso ocorre quando invasores inserem um código SQL mal-intencionado por meio dos campos de entrada do usuário. Isso pode permitir acesso não autorizado aos dados do banco de dados. É recomendável validar e limpar com cuidado todas as entradas do usuário antes do processamento usando variableMap para proteção contra ataques de injeção de SQL. Se mapas de variáveis não forem usados, você será responsável por limpar os argumentos das operações do GraphQL. Uma maneira de fazer isso é fornecer etapas de validação específicas de entrada no modelo de mapeamento de solicitação antes da execução de uma instrução SQL em relação à API de dados. Vamos ver como podemos modificar o modelo de mapeamento de solicitação do exemplo listPetsByPriceRange. Em vez de contar apenas com a entrada do usuário, você pode fazer o seguinte:
#set($validMaxPrice = $util.matches("\d{1,3}[,\\.]?(\\d{1,2})?",$ctx.args.maxPrice)) #set($validMinPrice = $util.matches("\d{1,3}[,\\.]?(\\d{1,2})?",$ctx.args.minPrice)) #if (!$validMaxPrice || !$validMinPrice) $util.error("Provided price input is not valid.") #end { "version": "2018-05-29", "statements": [ "select * from Pets where price > :MIN and price < :MAX" ], "variableMap": { ":MAX": $util.toJson($ctx.args.maxPrice), ":MIN": $util.toJson($ctx.args.minPrice) } }
Outra maneira de proteger contra entradas invasivas ao executar resolvedores em relação à API de dados é usar instruções preparadas junto com o procedimento armazenado e entradas parametrizadas. Por exemplo, no resolvedor para listPets, defina o seguinte procedimento que executa select como uma instrução preparada:
CREATE PROCEDURE listPets (IN type_param VARCHAR(200)) BEGIN PREPARE stmt FROM 'SELECT * FROM Pets where type=?'; SET @type = type_param; EXECUTE stmt USING @type; DEALLOCATE PREPARE stmt; END
Crie isso na instância do Aurora Serverless v2.
aws rds-data execute-statement --resource-arn "arn:aws:rds:us-east-1:xxxxxxxxxxxx:cluster:http-endpoint-test" \ --schema "mysql" --secret-arn "arn:aws:secretsmanager:us-east-1:xxxxxxxxxxxx:secret:httpendpoint-xxxxxx" \ --region us-east-1 --database "DB_NAME" \ --sql "CREATE PROCEDURE listPets (IN type_param VARCHAR(200)) BEGIN PREPARE stmt FROM 'SELECT * FROM Pets where type=?'; SET @type = type_param; EXECUTE stmt USING @type; DEALLOCATE PREPARE stmt; END"
O código de resolvedor resultante para listPets foi simplificado, pois agora simplesmente chamamos o procedimento armazenado. No mínimo, qualquer entrada de string deve ter aspas simples com caracteres de escape.
#set ($validType = $util.isString($ctx.args.type) && !$util.isNullOrBlank($ctx.args.type)) #if (!$validType) $util.error("Input for 'type' is not valid.", "ValidationError") #end { "version": "2018-05-29", "statements": [ "CALL listPets(:type)" ] "variableMap": { ":type": $util.toJson($ctx.args.type.replace("'", "''")) } }
Uso das strings de escape
Use aspas simples para marcar o início e o fim dos literais de string em uma instrução SQL; por exemplo, 'some string value'. Para permitir que valores de string com um ou mais caracteres de aspas simples (') sejam usados em uma string, cada um deve ser substituído por duas aspas simples (''). Por exemplo, se a string de entrada for Nadia's dog, você deverá inserir caracteres de escape nela para a instrução SQL, como
update Pets set type='Nadia''s dog' WHERE id='1'