기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.
AWS AppSync에서 Aurora PostgreSQL 및 데이터 API 사용
를 사용하여 GraphQL API를 Aurora PostgreSQL 데이터베이스에 연결하는 방법을 알아봅니다 AWS AppSync. 이 통합을 통해 GraphQL 작업을 통해 SQL 쿼리 및 변형을 실행하여 확장 가능한 데이터 기반 애플리케이션을 구축할 수 있습니다.는 데이터 API로 활성화된 Amazon Aurora 클러스터에 대해 SQL 문을 실행하기 위한 데이터 소스를 AWS AppSync 제공합니다. AWS AppSync 해석기를 사용하여 GraphQL 쿼리, 변형 및 구독과 함께 데이터 API에 대해 SQL 문을 실행할 수 있습니다.
이 자습서를 시작하기 전에 AWS 서비스 및 GraphQL 개념을 기본적으로 숙지해야 합니다.
참고
이 자습서에서는 US-EAST-1
리전을 사용합니다.
Aurora PostgreSQL 데이터베이스 설정
Amazon RDS 데이터 소스를에 추가하기 전에 다음을 AWS AppSync수행합니다.
Aurora Serverless v2 클러스터에서 데이터 API를 활성화합니다.
를 사용하여 보안 암호 구성 AWS Secrets Manager
다음 AWS CLI 명령을 사용하여 클러스터를 생성합니다.
aws rds create-db-cluster \ --db-cluster-identifier appsync-tutorial \ --engine aurora-postgresql \ --engine-version 16.6 \ --serverless-v2-scaling-configuration MinCapacity=0,MaxCapacity=1 \ --master-username USERNAME \ --master-user-password COMPLEX_PASSWORD \ --enable-http-endpoint
그러면 클러스터에 대한 ARN이 반환됩니다. 클러스터를 생성한 후 다음 AWS CLI 명령을 사용하여 Serverless v2 인스턴스를 추가해야 합니다.
aws rds create-db-instance \ --db-cluster-identifier appsync-tutorial \ --db-instance-identifier appsync-tutorial-instance-1 \ --db-instance-class db.serverless \ --engine aurora-postgresql
참고
이러한 엔드포인트가 활성화되려면 시간이 걸립니다. 클러스터의 연결 및 보안 탭에 있는 RDS 콘솔에서 상태를 확인할 수 있습니다.
다음 AWS CLI 명령을 사용하여 클러스터 상태를 확인합니다.
aws rds describe-db-clusters \ --db-cluster-identifier appsync-tutorial \ --query "DBClusters[0].Status"
이전 단계의 USERNAME
및를 사용하여 다음과 같은 AWS CLI 입력 파일을 사용하여 AWS Secrets Manager 콘솔 또는 COMPLEX_PASSWORD
를 통해 보안 암호를 생성합니다.
{ "username": "USERNAME", "password": "COMPLEX_PASSWORD" }
이를 파라미터로 AWS CLI에 전달합니다.
aws secretsmanager create-secret \ --name appsync-tutorial-rds-secret \ --secret-string file://creds.json
그러면 암호에 대한 ARN이 반환됩니다. AWS AppSync 콘솔에서 데이터 소스를 생성할 때 나중에 사용할 수 있도록 Aurora Serverless v2 클러스터의 ARN과 보안 암호를 기록해 둡니다.
데이터베이스 및 테이블 생성
먼저 라는 데이터베이스를 생성합니다TESTDB
. PostgreSQL에서 데이터베이스는 테이블 및 기타 SQL 객체를 포함하는 컨테이너입니다. API에 추가 AWS AppSync 하기 전에 Aurora Serverless v2 클러스터가 올바르게 구성되었는지 확인합니다. 먼저 다음과 같이 --sql
파라미터를 사용하여 TESTDB 데이터베이스를 생성합니다.
aws rds-data execute-statement \ --resource-arn "arn:aws:rds:us-east-1:111122223333 ISN:cluster:appsync-tutorial" \ --secret-arn "arn:aws:secretsmanager:us-east-1:111122223333 ISN:secret:appsync-tutorial-rds-secret" \ --sql "create DATABASE \"testdb\"" \ --database "postgres"
오류 없이 실행되면 create table
명령을 사용하여 두 개의 테이블을 추가합니다.
aws rds-data execute-statement \ --resource-arn "arn:aws:rds:us-east-1:111122223333 ISN:cluster:appsync-tutorial" \ --secret-arn "arn:aws:secretsmanager:us-east-1:111122223333 ISN: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:111122223333 ISN:cluster:appsync-tutorial" \ --secret-arn "arn:aws:secretsmanager:us-east-1:111122223333 ISN: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 v2 Data API가 구성된 테이블로 실행 중이므로 이제 GraphQL 스키마를 생성합니다. API 생성 마법사를 사용하여 기존 데이터베이스에서 테이블 구성을 가져와 API를 빠르게 생성할 수 있습니다.
시작하려면 다음과 같이 하십시오.
-
AWS AppSync 콘솔에서 API 생성을 선택한 다음 Amazon Aurora 클러스터로 시작을 선택합니다.
-
API 이름과 같은 API 세부 정보를 지정한 다음 API를 생성할 데이터베이스를 선택합니다.
-
데이터베이스 유형을 선택합니다. 필요한 경우 리전을 업데이트한 다음 Aurora 클러스터 및 TESTDB 데이터베이스를 선택합니다.
-
암호를 선택한 다음 가져오기를 선택합니다.
-
테이블이 검색되면 유형 이름을 업데이트하십시오.
Todos
를Todo
로,Tasks
를Task
로 변경하십시오. -
스키마 미리 보기를 선택하여 생성된 스키마를 미리 볼 수 있습니다. 스키마는 다음과 비슷한 모습이 됩니다.
type Todo { id: Int! description: String! due: AWSDate! createdAt: String } type Task { id: Int! todoId: Int! description: String }
-
역할의 경우 새 역할을 AWS AppSync 생성하거나 아래 역할과 유사한 정책을 사용하여 역할을 생성할 수 있습니다.
이 정책에는 역할 액세스 권한을 부여하는 문이 두 개 있습니다. 첫 번째 리소스는 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
유형에는 유사한 필드와 해석기가 첨부되어 있습니다. 몇 가지 해석기를 좀 더 자세히 살펴보겠습니다.
Mutation.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를 반환할 수 있으므로 다음과 같이 결과를 생성하고 단일 요청으로 반환하는 데 신뢰할 수 있습니다.
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" } } }
Query.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 } } }
Mutation.updateTodo
Todo
를 update
할 수도 있습니다. 쿼리 편집기에서 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 } }
create
및 list
작업을 처리한 방식과 마찬가지로 해석기를 업데이트하여 DATE
에 due
필드를 캐스팅할 수 있습니다. 이러한 변경 사항을 다음과 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 } }
Mutation.deleteTodo
deleteTodo
변형으로 Todo
를 delete
할 수 있습니다. 이는 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 문을 작성합니다. createPgStatement
는 한 번에 최대 두 개의 SQL 요청을 처리할 수 있습니다. 이를 사용하여 하나의 쿼리를 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