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 Postgre SQL com dados em API AWS AppSync
AWS AppSync fornece uma fonte de dados para executar SQL declarações em clusters do Amazon Aurora que são habilitados com dados. API Você pode usar AWS AppSync resolvedores para executar SQL instruções nos dados API com consultas, mutações e assinaturas do GraphQL.
nota
Este tutorial usa a Região US-EAST-1
.
Criar clusters
Antes de adicionar uma fonte de RDS dados da Amazon AWS AppSync, primeiro habilite os dados API em um cluster Aurora Serverless. Você também deve configurar um segredo usando AWS Secrets Manager. Para criar um cluster do Aurora Sem Servidor, é possível usar a AWS CLI:
aws rds create-db-cluster \ --db-cluster-identifier appsync-tutorial \ --engine aurora-postgresql --engine-version 13.11 \ --engine-mode serverless \ --master-username USERNAME \ --master-user-password COMPLEX_PASSWORD
Isso retornará um ARN para o cluster. É possível conferir o status do cluster com o comando:
aws rds describe-db-clusters \ --db-cluster-identifier appsync-tutorial \ --query "DBClusters[0].Status"
Crie um segredo por meio do 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 paraCLI:
aws secretsmanager create-secret \ --name appsync-tutorial-rds-secret \ --secret-string file://creds.json
Isso retornará e ARN recuperará o segredo. Anote o cluster e o segredo ARN do Aurora Serverless para mais tarde ao criar uma fonte de dados no console. AWS AppSync
Habilitando dados API
Depois que o status do cluster mudar paraavailable
, habilite os dados API seguindo a RDSdocumentação da Amazon. Os dados API devem ser ativados antes de serem adicionados como fonte AWS AppSync de dados. Você também pode ativar os dados API usando AWS CLI:
aws rds modify-db-cluster \ --db-cluster-identifier appsync-tutorial \ --enable-http-endpoint \ --apply-immediately
Criar o banco de dados e uma tabela
Depois de habilitar seus dadosAPI, verifique se eles funcionam usando o aws rds-data
execute-statement
comando no AWS CLI. Isso garante que seu cluster Aurora Serverless seja configurado corretamente antes de adicioná-lo ao. AWS AppSync API Primeiro, crie um TESTDBbanco de dados com o --sql
parâmetro:
aws rds-data execute-statement \ --resource-arn "arn:aws:rds:us-east-1:123456789012:cluster:appsync-tutorial" \ --secret-arn "arn:aws:secretsmanager:us-east-1:123456789012:secret:appsync-tutorial-rds-secret" \ --sql "create DATABASE \"testdb\""
Se isso for executado sem erros, inclua duas tabelas com o comando create table
:
aws rds-data execute-statement \ --resource-arn "arn:aws:rds:us-east-1:123456789012:cluster:appsync-tutorial" \ --secret-arn "arn:aws:secretsmanager:us-east-1:123456789012:secret:appsync-tutorial-rds-secret" \ --database "testdb" \ --sql 'create table public.todos (id serial constraint todos_pk primary key, description text not null, due date not null, "createdAt" timestamp default now());' aws rds-data execute-statement \ --resource-arn "arn:aws:rds:us-east-1:123456789012:cluster:appsync-tutorial" \ --secret-arn "arn:aws:secretsmanager:us-east-1:123456789012:secret:appsync-tutorial-rds-secret" \ --database "testdb" \ --sql 'create table public.tasks (id serial constraint tasks_pk primary key, description varchar, "todoId" integer not null constraint tasks_todos_id_fk references public.todos);'
Se tudo funcionar sem problemas, agora você pode adicionar o cluster como fonte de dados no seuAPI.
Criar um esquema do GraphQL
Agora que seus dados API sem servidor do Aurora estão sendo executados com tabelas configuradas, criaremos um esquema do GraphQL. Você pode fazer isso manualmente, mas AWS AppSync permite que você comece rapidamente importando a configuração da tabela de um banco de dados existente usando o assistente de API criação.
Para começar:
-
No AWS AppSync console, escolha Criar e, em seguidaAPI, Iniciar com um cluster Amazon Aurora.
-
Especifique API detalhes como APInome e selecione seu banco de dados para gerar API o.
-
Selecione o banco de dados. Se necessário, atualize a região e escolha seu cluster e TESTDBbanco de dados do Aurora.
-
Selecione o segredo e escolha Importar.
-
Depois que as tabelas forem descobertas, atualize os nomes dos tipos. Altere
Todos
paraTodo
eTasks
paraTask
. -
Visualize o esquema gerado selecionando Visualizar esquema. O esquema terá a seguinte aparência:
type Todo { id: Int! description: String! due: AWSDate! createdAt: String } type Task { id: Int! todoId: Int! description: String }
-
Para a função, você pode AWS AppSync criar uma nova função ou criar uma com uma política semelhante à abaixo:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "rds-data:ExecuteStatement", ], "Resource": [ "arn:aws:rds:us-east-1:123456789012:cluster:appsync-tutorial", "arn:aws:rds:us-east-1:123456789012:cluster:appsync-tutorial:*" ] }, { "Effect": "Allow", "Action": [ "secretsmanager:GetSecretValue" ], "Resource": [ "arn:aws:secretsmanager:us-east-1:123456789012:secret:your:secret:arn:appsync-tutorial-rds-secret", "arn:aws:secretsmanager:us-east-1:123456789012:secret:your:secret:arn:appsync-tutorial-rds-secret:*" ] } ] }
Observe que há duas declarações nesta política à qual você está concedendo acesso ao perfil. O primeiro recurso é seu cluster Aurora e o segundo é seu. AWS Secrets Manager ARN
Escolha Avançar, revise os detalhes da configuração e escolha Criar API. Agora você tem um totalmente operacionalAPI. Você pode revisar todos os detalhes do seu API na página Esquema.
Resolvedores para RDS
O fluxo API de criação criou automaticamente os resolvedores para interagir com nossos tipos. Se você consultar a página Esquema, encontrará os resolvedores necessários para:
-
Criar um
todo
por meio do campoMutation.createTodo
. -
Atualizar um
todo
por meio do campoMutation.updateTodo
. -
Excluir um
todo
por meio do campoMutation.deleteTodo
. -
Obter um único
todo
por meio do campoQuery.getTodo
. -
Listar todos os
todos
por meio do campoQuery.listTodos
.
Você encontrará campos e resolvedores semelhantes anexados para o tipo Task
. Vamos examinar com mais cuidado alguns dos resolvedores.
Mutação. createTodo
No editor de esquemas no AWS AppSync console, no lado direito, escolha testdb
próximo a. createTodo(...): Todo
O código do resolvedor usa a função insert
do módulo do rds
para criar dinamicamente uma declaração de inserção que adiciona dados à tabela todos
. Como estamos trabalhando com o Postgres, podemos aproveitar a declaração returning
para recuperar os dados inseridos.
Vamos atualizar o resolvedor para especificar corretamente o tipo DATE
do campo due
:
import { util } from '@aws-appsync/utils'; import { insert, createPgStatement, toJsonObject, typeHint } from '@aws-appsync/utils/rds'; export function request(ctx) { const { input } = ctx.args; // if a due date is provided, cast is as `DATE` if (input.due) { input.due = typeHint.DATE(input.due) } const insertStatement = insert({ table: 'todos', values: input, returning: '*', }); return createPgStatement(insertStatement) } export function response(ctx) { const { error, result } = ctx; if (error) { return util.appendError( error.message, error.type, result ) } return toJsonObject(result)[0][0] }
Salve o resolvedor. A dica de tipo marca a propriedade due
no objeto de entrada como um tipo DATE
. Isso permite que o mecanismo Postgres interprete adequadamente o valor. Depois, atualize o esquema para remover o id
da entrada CreateTodo
. Como nosso banco de dados Postgres pode exibir o ID gerado, podemos confiar nele para criar e exibir o resultado como uma única solicitação:
input CreateTodoInput { due: AWSDate! createdAt: String description: String! }
Faça a alteração e atualize o esquema. Acesse o editor de consultas para adicionar um item ao banco de dados:
mutation CreateTodo { createTodo(input: {description: "Hello World!", due: "2023-12-31"}) { id due description createdAt } }
Você obtém o resultado:
{ "data": { "createTodo": { "id": 1, "due": "2023-12-31", "description": "Hello World!", "createdAt": "2023-11-14 20:47:11.875428" } } }
Consulta. listTodos
No editor de esquemas no console, à direita, selecione testdb
ao lado de listTodos(id: ID!): Todo
. O manipulador de solicitações usa a função de utilitário select para criar uma solicitação dinamicamente em runtime.
export function request(ctx) { const { filter = {}, limit = 100, nextToken } = ctx.args; const offset = nextToken ? +util.base64Decode(nextToken) : 0; const statement = select({ table: 'todos', columns: '*', limit, offset, where: filter, }); return createPgStatement(statement) }
Queremos filtrar todos
com base na data due
. Vamos atualizar o resolvedor no qual converter valores due
em DATE
. Atualize a lista de importações e o manipulador de solicitações:
import { util } from '@aws-appsync/utils'; import * as rds from '@aws-appsync/utils/rds'; export function request(ctx) { const { filter: where = {}, limit = 100, nextToken } = ctx.args; const offset = nextToken ? +util.base64Decode(nextToken) : 0; // if `due` is used in a filter, CAST the values to DATE. if (where.due) { Object.entries(where.due).forEach(([k, v]) => { if (k === 'between') { where.due[k] = v.map((d) => rds.typeHint.DATE(d)); } else { where.due[k] = rds.typeHint.DATE(v); } }); } const statement = rds.select({ table: 'todos', columns: '*', limit, offset, where, }); return rds.createPgStatement(statement); } export function response(ctx) { const { args: { limit = 100, nextToken }, error, result, } = ctx; if (error) { return util.appendError(error.message, error.type, result); } const offset = nextToken ? +util.base64Decode(nextToken) : 0; const items = rds.toJsonObject(result)[0]; const endOfResults = items?.length < limit; const token = endOfResults ? null : util.base64Encode(`${offset + limit}`); return { items, nextToken: token }; }
Vamos testar a consulta. No editor de consultas:
query LIST { listTodos(limit: 10, filter: {due: {between: ["2021-01-01", "2025-01-02"]}}) { items { id due description } } }
Mutação. updateTodo
Também é possível update
um Todo
. No editor de consultas, vamos atualizar o primeiro item Todo
de id
1
.
mutation UPDATE { updateTodo(input: {id: 1, description: "edits"}) { description due id } }
Observe que é preciso especificar o id
do item que você está atualizando. Também é possível determinar uma condição para atualizar somente um item que atenda a condições específicas. Por exemplo, poderemos editar o item somente se a descrição começar com edits
:
mutation UPDATE { updateTodo(input: {id: 1, description: "edits: make a change"}, condition: {description: {beginsWith: "edits"}}) { description due id } }
Assim como processamos as operações create
e list
, podemos atualizar o resolvedor para converter o campo due
em DATE
. Salve essas alterações em updateTodo
:
import { util } from '@aws-appsync/utils'; import * as rds from '@aws-appsync/utils/rds'; export function request(ctx) { const { input: { id, ...values }, condition = {}, } = ctx.args; const where = { ...condition, id: { eq: id } }; // if `due` is used in a condition, CAST the values to DATE. if (condition.due) { Object.entries(condition.due).forEach(([k, v]) => { if (k === 'between') { condition.due[k] = v.map((d) => rds.typeHint.DATE(d)); } else { condition.due[k] = rds.typeHint.DATE(v); } }); } // if a due date is provided, cast is as `DATE` if (values.due) { values.due = rds.typeHint.DATE(values.due); } const updateStatement = rds.update({ table: 'todos', values, where, returning: '*', }); return rds.createPgStatement(updateStatement); } export function response(ctx) { const { error, result } = ctx; if (error) { return util.appendError(error.message, error.type, result); } return rds.toJsonObject(result)[0][0]; }
Agora tente uma atualização com uma condição:
mutation UPDATE { updateTodo( input: { id: 1, description: "edits: make a change", due: "2023-12-12"}, condition: { description: {beginsWith: "edits"}, due: {ge: "2023-11-08"}}) { description due id } }
Mutação. deleteTodo
É possível delete
um Todo
com a mutação deleteTodo
. Isso funciona como a mutação updateTodo
, e é necessário especificar o id
do item a ser excluído:
mutation DELETE { deleteTodo(input: {id: 1}) { description due id } }
Redigir consultas personalizadas
Usamos os utilitários do rds
módulo para criar nossas SQL declarações. Também podemos redigir a própria declaração estática personalizada para interagir com o banco de dados. Primeiro, atualize o esquema para remover o id
da entrada CreateTask
.
input CreateTaskInput { todoId: Int! description: String }
Depois, crie algumas tarefas. Uma tarefa tem uma relação de chave externa com Todo
:
mutation TASKS { a: createTask(input: {todoId: 2, description: "my first sub task"}) { id } b:createTask(input: {todoId: 2, description: "another sub task"}) { id } c: createTask(input: {todoId: 2, description: "a final sub task"}) { id } }
Crie um campo no tipo Query
chamado getTodoAndTasks
:
getTodoAndTasks(id: Int!): Todo
Adicione um campo tasks
ao tipo Todo
:
type Todo { due: AWSDate! id: Int! createdAt: String description: String! tasks:TaskConnection }
Salve o esquema. No editor de esquemas no console, à direita, selecione Anexar resolvedor para getTodosAndTasks(id:
Int!): Todo
. Escolha sua fonte de RDS dados da Amazon. Atualize o resolvedor com o seguinte código:
import { sql, createPgStatement,toJsonObject } from '@aws-appsync/utils/rds'; export function request(ctx) { return createPgStatement( sql`SELECT * from todos where id = ${ctx.args.id}`, sql`SELECT * from tasks where "todoId" = ${ctx.args.id}`); } export function response(ctx) { const result = toJsonObject(ctx.result); const todo = result[0][0]; if (!todo) { return null; } todo.tasks = { items: result[1] }; return todo; }
Nesse código, usamos o modelo de sql
tag para escrever uma SQL declaração para a qual podemos passar com segurança um valor dinâmico em tempo de execução. createPgStatement
pode receber até duas SQL solicitações por vez. Usamos isso para enviar uma consulta ao todo
e outra para a tasks
. É possível fazer isso com uma declaração JOIN
ou qualquer outro método. A ideia é poder escrever sua própria SQL declaração para implementar sua lógica de negócios. Para usar a consulta no editor de consultas, podemos tentar o seguinte:
query TodoAndTasks { getTodosAndTasks(id: 2) { id due description tasks { items { id description } } } }
Excluir o cluster
Importante
A exclusão de um cluster é permanente. Revise o projeto com cuidado antes de realizar essa ação.
Para excluir o cluster:
$ aws rds delete-db-cluster \ --db-cluster-identifier appsync-tutorial \ --skip-final-snapshot