API 의 데이터에서 Aurora PostgreSQL 사용 AWS AppSync - AWS AppSync

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

API 의 데이터에서 Aurora PostgreSQL 사용 AWS AppSync

AWS AppSync 는 데이터 로 활성화된 Amazon Aurora 클러스터에 대한 SQL 문을 실행하기 위한 데이터 소스를 제공합니다API. AWS AppSync 해석기를 사용하여 GraphQL 쿼리, 돌연변이 및 구독을 API 사용하여 데이터에 대한 SQL 문을 실행할 수 있습니다.

참고

이 자습서에서는 US-EAST-1 리전을 사용합니다.

클러스터 생성

Amazon RDS 데이터 소스를 에 추가하기 전에 AWS AppSync먼저 Aurora Serverless 클러스터API에서 데이터를 활성화합니다. 또한 를 사용하여 보안 암호를 구성해야 합니다 AWS Secrets Manager. Aurora Serverless 클러스터를 생성하기 위해 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

그러면 클러스터에 ARN 대한 가 반환됩니다. 명령으로 클러스터의 상태를 확인할 수 있습니다.

aws rds describe-db-clusters \ --db-cluster-identifier appsync-tutorial \ --query "DBClusters[0].Status"

COMPLEX_PASSWORD 이전 단계의 USERNAME 및 를 사용하여 AWS Secrets Manager 콘솔 또는 AWS CLI 를 통해 다음과 같은 입력 파일로 보안 암호를 생성합니다.

{ "username": "USERNAME", "password": "COMPLEX_PASSWORD" }

에 파라미터로 전달합니다CLI.

aws secretsmanager create-secret \ --name appsync-tutorial-rds-secret \ --secret-string file://creds.json

이렇게 하면 보안 암호에 ARN 대한 가 반환됩니다. AWS AppSync 콘솔에서 데이터 소스를 생성할 때 나중에 사용할 수 있도록 Aurora Serverless 클러스터 및 보안 암호ARN의 를 기록해 둡니다.

데이터 활성화 API

클러스터 상태가 로 변경되면 Amazon RDS 설명서 에 API 따라 데이터를 available활성화합니다. 데이터를 데이터 소스로 추가하기 전에 AWS AppSync 활성화해야 API 합니다. 를 API 사용하여 데이터를 활성화할 수도 있습니다 AWS CLI.

aws rds modify-db-cluster \ --db-cluster-identifier appsync-tutorial \ --enable-http-endpoint \ --apply-immediately

데이터베이스 및 테이블 생성

데이터 를 활성화한 후 의 aws rds-data execute-statement 명령을 사용하여 데이터 가 작동하는지 API확인합니다 AWS CLI. 이렇게 하면 Aurora Serverless 클러스터를 에 추가하기 전에 올바르게 구성됩니다 AWS AppSync API. 먼저 --sql 파라미터를 사용하여 TESTDB 데이터베이스를 생성합니다.

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\""

오류 없이 실행되면 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);'

모든 것이 문제 없이 실행되는 경우 이제 클러스터를 에 데이터 소스로 추가할 수 있습니다API.

GraphQL 스키마 생성

이제 Aurora Serverless DataAPI가 구성된 테이블로 실행되므로 GraphQL 스키마를 생성합니다. 수동으로 이 작업을 수행할 수 있지만 API 생성 마법사를 사용하여 기존 데이터베이스에서 테이블 구성을 가져와 빠르게 시작할 수 AWS AppSync 있습니다.

시작하려면 다음과 같이 하십시오.

  1. AWS AppSync 콘솔에서 생성 API을 선택한 다음 Amazon Aurora 클러스터 로 시작합니다.

  2. API 이름 과 같은 API 세부 정보를 지정한 다음 데이터베이스를 선택하여 를 생성합니다API.

  3. 데이터베이스 유형을 선택합니다. 필요한 경우 리전을 업데이트한 다음 Aurora 클러스터와 TESTDB 데이터베이스를 선택합니다.

  4. 암호를 선택한 다음 가져오기를 선택합니다.

  5. 테이블이 검색되면 유형 이름을 업데이트하십시오. TodosTodo로, TasksTask로 변경하십시오.

  6. 스키마 미리 보기를 선택하여 생성된 스키마를 미리 볼 수 있습니다. 스키마는 다음과 비슷한 모습이 됩니다.

    type Todo { id: Int! description: String! due: AWSDate! createdAt: String } type Task { id: Int! todoId: Int! description: String }
  7. 역할의 경우 새 역할을 AWS AppSync 생성하거나 아래 역할과 유사한 정책을 사용하여 생성할 수 있습니다.

    { "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:*" ] } ] }

    이 정책에는 역할 액세스 권한을 부여하는 문이 두 개 있습니다. 첫 번째 리소스는 Aurora 클러스터이고 두 번째 리소스는 입니다 AWS Secrets Manager ARN.

    다음을 선택하고 구성 세부 정보를 검토한 다음 생성을 API선택합니다. 이제 가 완전히 작동합니다API. 스키마 API 페이지에서 의 전체 세부 정보를 검토할 수 있습니다.

에 대한 해석기 RDS

API 생성 흐름은 자동으로 해석기를 생성하여 유형과 상호 작용합니다. 스키마 페이지를 보면 다음에 필요한 해석기를 찾을 수 있습니다.

  • Mutation.createTodo 필드를 통해 todo를 생성하십시오.

  • Mutation.updateTodo 필드를 통해 todo를 업데이트하십시오.

  • Mutation.deleteTodo 필드를 통해 todo를 삭제하십시오.

  • Query.getTodo 필드를 통해 단일 todo를 가져오십시오.

  • todos 필드를 통해 Query.listTodos를 모두 나열하십시오.

Task 유형에는 유사한 필드와 해석기가 첨부되어 있습니다. 몇 가지 해석기를 좀 더 자세히 살펴보겠습니다.

돌연변이.createTodo

AWS AppSync 콘솔의 스키마 편집기 오른쪽에서 testdb 옆에 있는 를 선택합니다createTodo(...): Todo. 해석기 코드는 rds 모듈의 insert 함수를 사용하여 todos 테이블에 데이터를 추가하는 삽입 문을 동적으로 만듭니다. Postgres를 사용하고 있기 때문에 returning 문을 활용하여 삽입된 데이터를 다시 가져올 수 있습니다.

due 필드의 DATE 유형을 올바르게 지정하도록 해석기를 업데이트해 보겠습니다.

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] }

해석기를 저장합니다. 유형 힌트는 입력 객체의 due를 올바르게 DATE 유형으로 표시합니다. 이렇게 하면 Postgres 엔진이 값을 올바르게 해석할 수 있습니다. 다음으로 스키마를 업데이트하여 CreateTodo 입력에서 id를 제거합니다. Postgres 데이터베이스는 생성된 ID를 반환할 수 있으므로 단일 요청으로 이 ID를 사용하여 결과를 생성하고 반환할 수 있습니다.

input CreateTodoInput { due: AWSDate! createdAt: String description: String! }

스키마를 변경하고 업데이트하십시오. 쿼리 편집기로 이동하여 데이터베이스에 항목을 추가합니다.

mutation CreateTodo { createTodo(input: {description: "Hello World!", due: "2023-12-31"}) { id due description createdAt } }

결과는 다음과 같습니다.

{ "data": { "createTodo": { "id": 1, "due": "2023-12-31", "description": "Hello World!", "createdAt": "2023-11-14 20:47:11.875428" } } }

쿼리.listTodos

콘솔의 스키마 편집기 오른쪽에서 listTodos(id: ID!): Todo 옆에 있는 testdb를 선택합니다. 요청 핸들러는 선택 유틸리티 함수를 사용하여 런타임에 요청을 동적으로 작성합니다.

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) }

due 날짜를 기준으로 todos를 필터링하려고 합니다. due 값을 DATE로 캐스팅하도록 해석기를 업데이트해 보겠습니다. 가져오기 목록과 요청 핸들러를 업데이트하십시오.

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 }; }

쿼리를 실행해 보겠습니다. 쿼리 편집기:

query LIST { listTodos(limit: 10, filter: {due: {between: ["2021-01-01", "2025-01-02"]}}) { items { id due description } } }

돌연변이.updateTodo

Todoupdate할 수도 있습니다. 쿼리 편집기에서 id 1의 첫 번째 Todo 항목을 업데이트해 보겠습니다.

mutation UPDATE { updateTodo(input: {id: 1, description: "edits"}) { description due id } }

업데이트하려는 항목의 id를 지정해야 합니다. 특정 조건을 충족하는 항목만 업데이트하도록 조건을 지정할 수도 있습니다. 예를 들어 설명이 edits로 시작하는 경우에만 항목을 편집하고 싶을 수 있습니다.

mutation UPDATE { updateTodo(input: {id: 1, description: "edits: make a change"}, condition: {description: {beginsWith: "edits"}}) { description due id } }

createlist 작업을 처리한 방식과 마찬가지로 해석기를 업데이트하여 DATEdue 필드를 캐스팅할 수 있습니다. 이 변경 사항을 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]; }

이제 다음과 같은 조건을 적용하여 업데이트를 시도해 보십시오.

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 } }

돌연변이.deleteTodo

deleteTodo 변형으로 Tododelete할 수 있습니다. 이는 updateTodo 변형과 비슷하게 작동하며 삭제하려는 항목의 id를 지정해야 합니다.

mutation DELETE { deleteTodo(input: {id: 1}) { description due id } }

사용자 지정 쿼리 작성

rds 모듈 유틸리티를 사용하여 SQL 문을 생성했습니다. 데이터베이스와 상호 작용하는 사용자 지정 정적 문을 직접 작성할 수도 있습니다. 먼저 스키마를 업데이트하여 CreateTask 입력에서 id 필드를 제거합니다.

input CreateTaskInput { todoId: Int! description: String }

다음으로, 몇 가지 작업을 만듭니다. 작업에는 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 } }

getTodoAndTasks라는 Query 유형에 새 필드를 생성합니다.

getTodoAndTasks(id: Int!): Todo

Todo 유형에 tasks 필드를 추가합니다.

type Todo { due: AWSDate! id: Int! createdAt: String description: String! tasks:TaskConnection }

스키마를 저장합니다. 콘솔의 스키마 편집기 오른쪽에서 getTodosAndTasks(id: Int!): Todo에 대해 해석기 첨부를 선택합니다. Amazon RDS 데이터 소스를 선택합니다. 다음 코드로 해석기를 업데이트합니다.

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; }

이 코드에서는 sql 태그 템플릿을 사용하여 런타임에 동적 값을 안전하게 전달할 수 있는 SQL 문을 작성합니다. 는 한 번에 최대 2개의 SQL 요청을 취할 수 createPgStatement 있습니다. 이를 사용하여 하나의 쿼리를 todo에 보내고 다른 쿼리는 tasks에 보냅니다. JOIN 문이나 다른 방법을 사용해도 이 작업을 수행할 수 있었을 것입니다. 이 아이디어는 비즈니스 로직을 구현하기 위해 자체 SQL 문을 작성할 수 있습니다. 쿼리 편집기에서 쿼리를 사용하려면 다음과 같이 시도해 볼 수 있습니다.

query TodoAndTasks { getTodosAndTasks(id: 2) { id due description tasks { items { id description } } } }

모든 클러스터 삭제

중요

클러스터 삭제는 영구적입니다. 이 작업을 수행하기 전에 프로젝트를 철저하게 검토하십시오.

클러스터를 삭제하려면 다음과 같이 하십시오.

$ aws rds delete-db-cluster \ --db-cluster-identifier appsync-tutorial \ --skip-final-snapshot