本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
在 中使用 Aurora PostgreSQL 搭配資料 API AWS AppSync
了解如何使用 將您的 GraphQL API 連線至 Aurora PostgreSQL 資料庫 AWS AppSync。此整合可讓您透過 GraphQL 操作執行 SQL 查詢和變動,以建置可擴展的資料驅動型應用程式。 AWS AppSync 提供資料來源,以針對使用資料 API 啟用的 Amazon Aurora 叢集執行 SQL 陳述式。您可以使用 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"
透過 AWS Secrets Manager 主控台或 建立秘密, AWS CLI 並使用 USERNAME
和上一個步驟COMPLEX_PASSWORD
中的輸入檔案,如下所示:
{ "username": "USERNAME", "password": "COMPLEX_PASSWORD" }
將此做為參數傳遞至 AWS CLI:
aws secretsmanager create-secret \ --name appsync-tutorial-rds-secret \ --secret-string file://creds.json
這會傳回秘密的 ARN。記下 Aurora Serverless v2 叢集的 ARN 和 Secret,以供稍後在 AWS AppSync 主控台中建立資料來源時使用。
建立資料庫和資料表
首先,建立名為 的資料庫TESTDB
。在 PostgreSQL 中,資料庫是存放資料表和其他 SQL 物件的容器。驗證您的 Aurora Serverless v2 叢集已正確設定,再將其新增至您的 AWS AppSync API。首先,使用 --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 建立流程會自動建立解析程式,以與我們的類型互動。如果您查看結構描述頁面,您會找到一些混沌的解析程式。
-
todo
透過Mutation.createTodo
欄位建立 。 -
todo
透過Mutation.updateTodo
欄位更新 。 -
todo
透過Mutation.deleteTodo
欄位刪除 。 -
todo
透過Query.getTodo
欄位取得單一 。 -
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 引擎正確解譯值。接著,更新您的結構描述,id
從CreateTodo
輸入中移除 。由於 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
從主控台的結構描述編輯器右側,選擇 testdb
旁的 listTodos(id: ID!): Todo
。請求處理常式會使用選取公用程式函數,在執行時間動態建置請求。
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) }
我們希望todos
根據due
日期進行篩選。讓我們更新解析程式,將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
您也可以update
使用 Todo
。從查詢編輯器,讓我們更新第一個 id
Todo
項目1
。
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
操作的方式一樣,我們可以更新解析程式,將 due
欄位轉換為 DATE
。將這些變更儲存至 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
您可以Todo
具有 deleteTodo
變動的 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 } }
在名為 的Query
類型中建立新的欄位getTodoAndTasks
,如下所示。
getTodoAndTasks(id: Int!): Todo
將tasks
欄位新增至 Todo
類型,如下所示。
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