本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
搭配 使用 Aurora Serverless v2 AWS AppSync
使用 將您的 GraphQL API 連接至 Aurora Serverless 資料庫 AWS AppSync。此整合可讓您透過 GraphQL 查詢、變動和訂閱執行 SQL 陳述式,讓您有彈性地與關聯式資料互動。
注意
此教學會使用 US-EAST-1
區域。
優勢
GraphQL 與關聯式資料庫之間的無縫整合
能夠透過 GraphQL 介面執行 SQL 操作
搭配 Aurora Serverless v2 的無伺服器可擴展性
透過 AWS Secrets Manager 安全存取資料
透過輸入淨化防止 SQL 注入
靈活的查詢功能,包括篩選和範圍操作
常用案例
使用關聯式資料需求建置可擴展的應用程式
建立同時需要 GraphQL 彈性和 SQL 資料庫功能的 APIs
透過 GraphQL 變動和查詢管理資料操作
實作安全資料庫存取模式
在本教學課程中,您將學到以下內容。
設定 Aurora Serverless v2 叢集
啟用資料 API 功能
建立和設定資料庫結構
定義資料庫操作的 GraphQL 結構描述
實作查詢和變動的解析程式
透過適當的輸入清理來保護您的資料存取
透過 GraphQL 介面執行各種資料庫操作
設定資料庫叢集
將 Amazon RDS 資料來源新增至 之前 AWS AppSync,您必須先在 Aurora Serverless v2 叢集上啟用資料 API,並使用 設定秘密AWS Secrets Manager。您可以使用 建立 Aurora Serverless v2 叢集 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
這會傳回叢集的 ARN。
建立叢集之後,您必須使用下列命令新增 Aurora 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-mysql
注意
這些端點需要一些時間才能啟用。您可以在叢集的連線與安全索引標籤中的 Amazon 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 HttpRDSSecret --secret-string file://creds.json --region us-east-1
這會傳回秘密的 ARN。
記下 ARN (屬於 Aurora Serverless 叢集及 Secret) 以供日後建立資料來源時用於 AppSync 主控台。
啟用 Data API
您可以依照 RDS 文件中的說明,在您的叢集上啟用 Data API。Data API 必須先行啟用,才能新增為 AppSync 資料來源。
建立資料庫及資料表
啟用資料 API 後,您就可以確保它可與 中的 aws rds-data execute-statement
命令搭配使用 AWS CLI。這可確保您的 Aurora Serverless 叢集在經過正確設定後,才新增到您的 AppSync API。首先使用 --sql
參數建立名為 TESTDB 的資料庫,如下所示:
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"
如果這次執行沒有錯誤,則搭配 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"
如果所有執行都沒有問題,您就可以繼續將該叢集新增到您的 AppSync API。
GraphQL 結構描述
現在您的 Aurora Serverless Data API 已經啟動並搭配資料表運作,我們會建立 GraphQL 結構描述,並連接可執行變動和訂閱的解析程式。在 AWS AppSync 主控台中建立新的 API 並導覽至結構描述頁面,然後輸入以下內容:
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 }
儲存您的結構描述並瀏覽到 Data Sources (資料來源) 頁面,並建立新的資料來源。選取資料來源類型為 Relational database (關聯式資料庫),並提供易記名稱。使用您在上一個步驟中所建立的資料庫名稱,以及您所建立叢集的叢集 ARN。處理角色時,您可以使用 AppSync 來建立新角色,或是搭配類似下面政策來建立一個角色:
請注意,在您授予角色存取權的這個政策中有 2 個陳述式 。第一個資源是您的 Aurora Serverless 叢集,第二個資源是您的 AWS Secrets Manager ARN。您將需要先在 AppSync 資料來源組態中同時提供兩種 ARN 後,再按一下 Create (建立)。
將此做為 參數傳遞至 AWS CLI。
aws secretsmanager create-secret \ --name HttpRDSSecret \ --secret-string file://creds.json \ --region us-east-1
這會傳回秘密的 ARN。記下 Aurora Serverless 叢集的 ARN 和 Secret,以供稍後在 AWS AppSync 主控台中建立資料來源時使用。
建置您的資料庫結構
啟用資料 API 後,您就可以確保它可與 中的 aws rds-data execute-statement
命令搭配使用 AWS CLI。這將確保您的 Aurora Serverless v2 叢集在新增至 AWS AppSync API 之前已正確設定。首先,使用 --sql
參數建立名為 TESTDB 的資料庫,如下所示。
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"
如果執行時沒有錯誤,請使用下列建立資料表命令新增資料表。
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"
設計您的 API 介面
Aurora Serverless v2 Data API 啟動並使用資料表執行後,請建立 GraphQL 結構描述,並連接解析程式以執行變動和訂閱。在 AWS AppSync 主控台中建立新的 API,並導覽至主控台中的結構描述頁面,然後輸入以下內容。
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 }
儲存您的結構描述並瀏覽到 Data Sources (資料來源) 頁面,並建立新的資料來源。選擇資料來源類型的關聯式資料庫,並提供易記的名稱。使用您在上一個步驟中所建立的資料庫名稱,以及您所建立叢集的叢集 ARN。對於角色,您可以 AWS AppSync 建立新的角色,或使用類似下列的政策來建立角色。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "rds-data:DeleteItems", "rds-data:ExecuteSql", "rds-data:ExecuteStatement", "rds-data:GetItems", "rds-data:InsertItems", "rds-data:UpdateItems" ], "Resource": [ "arn:aws:rds:us-east-1:
111122223333
:cluster:mydbcluster", "arn:aws:rds:us-east-1:111122223333
:cluster:mydbcluster:*" ] }, { "Effect": "Allow", "Action": [ "secretsmanager:GetSecretValue" ], "Resource": [ "arn:aws:secretsmanager:us-east-1:111122223333
:secret:mysecret", "arn:aws:secretsmanager:us-east-1:111122223333
:secret:mysecret:*" ] } ] }
請注意,在您授予角色存取權的這個政策中有 2 個陳述式 。第一個資源是您的 Aurora Serverless v2 叢集,第二個是您的 AWS Secrets Manager ARN。在按一下建立之前,您需要在 AWS AppSync 資料來源組態中提供這兩個 ARNs。
將您的 API 連線至資料庫操作
現在我們有有效的 GraphQL 結構描述和 RDS 資料來源,您可以將解析程式連接到結構描述的 GraphQL 欄位。我們的 API 提供下列功能:
-
使用 Mutation.createPet 欄位建立寵物
-
使用 Mutation.updatePet 欄位更新寵物
-
使用 Mutation.deletePet 欄位刪除寵物
-
透過 Query.getPet 欄位取得單一使用
-
使用 Query.listPets 欄位列出所有
-
使用 Query.listPetsByPriceRange 欄位列出價格範圍內的寵物
Mutation.createPet
從 AWS AppSync 主控台的結構描述編輯器,選擇 的連接解析程式createPet(input: CreatePetInput!): Pet
。選擇 RDS 資料來源。在 request mapping template (要求映射範本) 區段中,新增下列範本:
#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) } }
系統會根據陳述式陣列中的順序依序執行 SQL 陳述式。結果將以相同順序傳回。由於這是一個變動,因此您將在插入後執行選取陳述式,以擷取遞交的值,以填入 GraphQL 回應映射範本。
在 response mapping template (回應映射範本) 區段中,新增下列範本:
$utils.toJson($utils.rds.toJsonObject($ctx.result)[1][0])
由於陳述式有兩個 SQL 查詢,所以我們需要使用下列程式碼,指定自資料庫傳回矩陣中的第二個結果:$utils.rds.toJsonString($ctx.result))[1][0])
。
Mutation.updatePet
從 AWS AppSync 主控台的結構描述編輯器中,選擇連接解析程式。 updatePet(input: UpdatePetInput!): Pet
選擇您的 RDS 資料來源。在請求映射範本區段中,新增下列範本。
{ "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) } }
在回應映射範本區段中,新增下列範本。
$utils.toJson($utils.rds.toJsonObject($ctx.result)[1][0])
Mutation.deletePet
從 AWS AppSync 主控台的結構描述編輯器中,選擇連接解析程式。 deletePet(input: DeletePetInput!): Pet
選擇您的 RDS 資料來源。在請求映射範本區段中,新增下列範本。
{ "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" } }
在回應映射範本區段中,新增下列範本。
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0][0])
Query.getPet
現在已為您的結構描述建立變動,請連接三個查詢,展示如何取得個別項目、清單和套用 SQL 篩選。從 AWS AppSync 主控台的結構描述編輯器中,選擇連接 解析程式getPet(id: ID!): Pet
。選擇您的 RDS 資料來源。在請求映射範本區段中,新增下列範本。
{ "version": "2018-05-29", "statements": [ $util.toJson("select * from Pets WHERE id=:ID") ], "variableMap": { ":ID": "$ctx.args.id" } }
在 response mapping template (回應映射範本) 區段中,新增下列範本:
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0][0])
Query.listPets
從 AWS AppSync 主控台中的結構描述編輯器,選擇 的連接解析程式getPet(id: ID!): Pet
。選擇您的 RDS 資料來源。在請求映射範本區段中,新增下列範本。
{ "version": "2018-05-29", "statements": [ "select * from Pets" ] }
在回應映射範本區段中,新增下列範本。
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])
Query.listPetsByPriceRange
從 AWS AppSync 主控台中的結構描述編輯器,選擇 的連接解析程式getPet(id: ID!): Pet
。選擇您的 RDS 資料來源。在請求映射範本區段中,新增下列範本。
{ "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) } }
在 response mapping template (回應映射範本) 區段中,新增下列範本:
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])
透過 API 修改您的資料
現在,您已運用 SQL 陳述式設定您的所有解析程式,並已將 GraphQL API 連接到您的 Serverless Aurora Data API,您可以開始執行變動和查詢了。In AWS AppSync 主控台,選擇查詢索引標籤,然後輸入下列內容來建立寵物:
mutation add { createPet(input : { type:fish, price:10.0 }){ id type price } }
回應應該包含如下的 id、type 和 price:
{ "data": { "createPet": { "id": "c6fedbbe-57ad-4da3-860a-ffe8d039882a", "type": "fish", "price": "10.0" } } }
您可以執行 updatePet 變動,修改此項目:
mutation update { updatePet(input : { id: ID_PLACEHOLDER, type:bird, price:50.0 }){ id type price } }
請注意,我們使用先前從 createPet 操作傳回的 ID。這將是您的記錄在解析程式運用 $util.autoId()
時的唯一值。您可以用類似的方式刪除記錄:
mutation delete { deletePet(input : {id:ID_PLACEHOLDER}){ id type price } }
運用第一個變動,搭配 price 的幾個不同值,建立一些記錄,然後執行一些查詢。
擷取您的資料
仍在主控台的查詢索引標籤中,請使用下列陳述式列出您已建立的所有記錄。
query allpets { listPets { id type price } }
透過下列 GraphQL 查詢,利用 Query.listPetsByPriceRange 映射範本where price > :MIN and price < :MAX
中具有 的 SQL WHERE 述詞:
query petsByPriceRange { listPetsByPriceRange(min:1, max:11) { id type price } }
您應該只會看到 price 超過 $1 元或不到 $10 元的記錄。最後,您可以執行查詢來擷取個別記錄,如下所示:
query onePet { getPet(id:ID_PLACEHOLDER){ id type price } }
保護您的資料存取
SQL Injection 是資料庫應用程式中的安全漏洞。當攻擊者透過使用者輸入欄位插入惡意 SQL 程式碼時,就會發生這種情況。這可以允許未經授權存取資料庫資料。建議您在處理所有使用者輸入之前,使用 仔細驗證並清除,variableMap
以防止 SQL Injection 攻擊。如果未使用變數映射,您必須負責清理其 GraphQL 操作的引數。達成這個淨化的一種方法是先在要求映射範本中提供輸入特定驗證步驟,接著再對 Data API 執行 SQL 陳述式。讓我們來看看如何修改 listPetsByPriceRange
範例的請求映射範本。您可以執行以下操作,而不再只是依賴使用者輸入:
#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) } }
在對 Data API 執行解析程式時防堵惡意輸入的另外一種方法,就是同時使用預備的陳述式來搭配預存程序和參數化的輸入。例如,在 listPets
的解析程式中,定義下列執行 select 為預先準備陳述式的程序:
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
在 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"
針對 listPets 產生的解析程式碼變得簡單,因為我們現在只要呼叫預存程序。至少,任何字串輸入都應將單引號逸出。
#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("'", "''")) } }
使用逸出字串
使用單引號在 SQL 陳述式中標記字串常值的開頭和結尾,例如 。 'some string value'
若要允許在字串中使用具有一或多個單引號字元 ('
) 的字串值,必須以兩個單引號 (''
) 取代每個字串值。例如,如果輸入字串是 Nadia's dog
,則您會將其逸出為如下的 SQL 陳述式:
update Pets set type='Nadia''s dog' WHERE id='1'