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 que você execute instruções SQL por meio de consultas, mutações e assinaturas do GraphQL, oferecendo uma maneira flexível de interagir com seus 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 sem servidor com o Aurora Serverless v2
Acesso seguro aos dados por meio do AWS Secrets Manager
Proteção contra injeção de SQL por meio de higienização de entrada
Recursos flexíveis de consulta, incluindo operações de filtragem e alcance
Casos de uso comuns
Criação de aplicativos escaláveis com requisitos de dados relacionais
Para criar APIs isso, é necessário tanto a flexibilidade do GraphQL quanto os recursos do banco de dados SQL
Gerenciando operações de dados por meio de mutações e consultas do GraphQL
Implementação de padrões seguros de acesso ao banco
Neste tutorial, você aprenderá o seguinte.
Configurar um cluster Aurora Serverless v2
Ativar a funcionalidade da API de dados
Crie e configure estruturas de banco de dados
Definir esquemas do GraphQL para operações de banco de dados
Implemente resolvedores para consultas e mutações
Proteja seu acesso aos dados por meio da higienização adequada da entrada
Execute várias operações de banco de dados por meio de interfaces GraphQL
Tópicos
Configurando seu cluster de 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 Aurora Serverless v2 usando: 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ê deve 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
Esses endpoints demoram para serem ativados. Você pode verificar seu 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 e segredo sem servidor do Aurora para mais tarde ao criar uma fonte de dados no console. AWS AppSync
Crie sua estrutura de 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 --sql
parâmetro 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 seguinte 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"
Projete sua interface de API
Depois que a API de dados Aurora Serverless v2 estiver em funcionamento com uma tabela, crie um esquema GraphQL e anexe 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 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 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.
Conecte sua API às operações do banco de dados
Agora que temos um esquema GraphQL válido e uma fonte de dados RDS, você pode anexar resolvedores aos campos do GraphQL ao seu esquema. Nossa API oferecerá os seguintes recursos:
-
crie um animal de estimação usando o campo mutation.createPet
-
atualize um animal de estimação usando o campo mutation.updatePet
-
exclua um animal de estimação usando o campo mutation.deletePet
-
obtenha um único uso por meio do 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
. Selecione 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 isso é uma mutação, você executará uma instrução select após a inserção para recuperar os valores confirmados a fim de preencher o modelo de mapeamento de resposta 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 sua fonte de dados do RDS. Na seção do modelo de mapeamento da solicitação, 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 do modelo de mapeamento de resposta, 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 sua fonte de dados do RDS. Na seção do modelo de mapeamento da solicitação, 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 do modelo de mapeamento de resposta, adicione o modelo a seguir.
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0][0])
Query.getPet
Agora que as mutações foram criadas para seu esquema, conecte as três consultas para mostrar 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 sua fonte de dados do RDS. Na seção do modelo de mapeamento da solicitação, 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 sua fonte de dados do RDS. Na seção do modelo de mapeamento da solicitação, adicione o modelo a seguir.
{ "version": "2018-05-29", "statements": [ "select * from Pets" ] }
Na seção do modelo de mapeamento de resposta, 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 sua fonte de dados do RDS. Na seção do modelo de mapeamento da solicitação, 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])
Modifique seus 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.
Recupere seus dados
Ainda na guia Consultas do console, use a instrução a seguir para listar todos os registros que você criou.
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 } }
Proteja seu acesso aos dados
A injeção de SQL é uma vulnerabilidade de segurança em aplicativos de banco de dados. Isso ocorre quando os invasores inserem um código SQL malicioso por meio dos campos de entrada do usuário. Isso pode permitir acesso não autorizado aos dados do banco de dados. Recomendamos que você valide e limpe cuidadosamente todas as entradas do usuário antes do processamento, usando variableMap
para proteção contra ataques de injeção de SQL. Se os mapas de variáveis não forem usados, você será responsável por limpar os argumentos de suas 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 em sua instância 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("'", "''")) } }
Usando sequências 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'