尝试在 Azure API Management 的 GraphQL API的解析器中使用 Cosmos DB 数据源
首先
API管理是一项可以轻松管理API的服务,不仅可以创建REST API,还可以创建GraphQL的API。
在API管理中,我们过去可以将现有的REST API作为数据源来创建GraphQL的API,但现在也可以使用Cosmos DB和Azure SQL Database作为数据源。(*预览阶段)
通过使用这些数据源,我们可以直接将数据库作为API公开,而无需单独准备后端。
在上一篇文章中,我们使用了Azure SQL Database作为数据源,但在本文中,我想使用Cosmos DB的数据源,尝试在API管理中创建GraphQL的API。
Azure SQL Database 版 => Azure SQL 数据库版
前提(one option: 前提)
-
- API Management のリソースが作成済みであること。
この記事では API Management のリソース作成手順については説明しません。
価格レベルは何でも良いと思いますが、執筆時は従量課金レベルで検証しています。
Cosmos DB のリソースが作成済みであること。
この記事では Cosmos DB のリソース作成手順については説明しません。
Azure CLI がインストール済みであること。
この記事では Azure CLI のインストール手順については説明しません。
事前准备
基本上,我们会根据文件的指示继续进行。
启用 API 管理的托管 ID。
与SQL数据库版本相同。
为 Cosmos DB 分配角色
在终端上执行以下命令,为托管ID授予Cosmos DB角色。
resourceGroupName="<リソースグループ名>"
cosmosName="<Cosmos DB のリソース名>"
apimName="<API Management のリソース名>"
# API Management のプリンシパルID を取得する
apimPrincipal=$(az apim show \
--resource-group $resourceGroupName \
--name $apimName \
--query "identity.principalId" \
--output tsv)
# Cosmos DB のリソースID を取得する
cosmosdbId=$(
az cosmosdb show \
--resource-group $resourceGroupName \
--name $cosmosName \
--query id \
--output tsv
)
# API Management の マネージド ID に Cosmos DB のロールを付与する
# ここでは「Cosmos DB Built-in Data Contributor」を付与
az cosmosdb sql role assignment create \
--resource-group $resourceGroupName \
--account-name $cosmosName \
--role-definition-name "Cosmos DB Built-in Data Contributor" \
--principal-id $apimPrincipal \
--scope $cosmosdbId
创建数据库和容器
创建一个适当的数据库和容器,并输入适当的数据。
创建 API
创建Schema文件
由于在创建GraphQL API时需要选择Schema文件,因此需要提前创建。本次选择按以下方式创建。
type Query {
getUser(id: ID!): User!
getUsers(): UserList!
}
type Mutation {
createUser(input: CreateUserInput!): User!
updateUser(input: UpdateUserInput!): User!
deleteUser(id: ID!): Boolean!
}
type User {
id: ID!
name: String!
age: Int!
}
type UserList {
items: [User!]!
hasNextPage: Boolean!
endCursor: String
}
input UpdateUserInput {
id: ID!
name: String!
age: Int!
}
input CreateUserInput {
id: ID!
name: String!
age: Int!
}
添加 GraphQL API
※与 SQL 数据库版本相同。
创建解析器


设置政策
网络设置(通用)
<cosmosdb-data-source>
<!-- 接続設定 -->
<connection-info>
<connection-string use-managed-identity="true">
AccountEndpoint=https://<Cosmos DB リソース名>.documents.azure.com:443/;
</connection-string>
<database-name>demo-db</database-name>
<container-name>users</container-name>
</connection-info>
<!-- 省略 -->
</cosmosdb-data-source>
为了使用托管标识连接,将属性use-managed-identity=”true”指定在connection-string中。
指定Cosmos DB数据库名称在database-name中。
指定Cosmos DB容器名称在container-name中。
获取单一结果
获取单个数据的策略如下所示:(getUser)
<!-- getUser -->
<cosmosdb-data-source>
<!-- 接続設定は省略 -->
<read-request>
<id>
@(context.GraphQL.Arguments["id"].Value<string>())
</id>
<partition-key>
@(context.GraphQL.Arguments["id"].Value<string>())
</partition-key>
</read-request>
</cosmosdb-data-source>
设置read-request要素。
与SQL数据库不同,这里只需要指定键(id、partition-key),无需编写查询。
可以使用id、partition-key来引用请求参数。
要引用,请指定一个策略表达式。
context.GraphQL.Arguments中包含了在请求时指定的参数。
获取多个数据
如果需要获取多行结果,则使用以下策略(获取用户)。
<!-- getUsers -->
<cosmosdb-data-source>
<!-- 接続設定は省略 -->
<query-request>
<sql-statement>
SELECT * FROM c
</sql-statement>
</query-request>
</cosmosdb-data-source>
如果结果集有多行的话,与 SQL 数据库一样,在 sql-statement 要素中编写查询。
另外,您还可以在sql-statement中使用在parameters中指定的参数,就像在SQL Database中一样。
<!-- getUsers -->
<cosmosdb-data-source>
<!-- 接続設定は省略 -->
<query-request>
<sql-statement>
- SELECT * FROM c
+ SELECT * FROM c WHERE CONTAINS(c.name, @name)
</sql-statement>
+ <parameters>
+ <parameter name="@name">@(context.GraphQL.Arguments["name"])</parameter>
+ </parameters>
</query-request>
</cosmosdb-data-source>
更新系 – 升级体系
如果是更新操作的话,将采取以下策略。(针对createUser的情况)
<!-- createUser -->
<cosmosdb-data-source>
<!-- 接続設定は省略 -->
<write-request type="upsert">
<partition-key>
@(context.GraphQL.Arguments["input"]["id"].Value<string>())
</partition-key>
<set-body template="liquid">
{
"id":"{{body.arguments.input.id}}",
"name":"{{body.arguments.input.name}}",
"age":{{body.arguments.input.age}}
}
</set-body>
</write-request>
</cosmosdb-data-source>
请设置write-request要素。
与获取单一数据一样,不需要编写查询,只需指定键(partition-key)。
换句话说,在Cosmos DB中不支持通过查询进行更新,因此无法实现。
通过write-request要素的type属性指定更新的类型。
可以指定insert(插入)、replace(替换)和upsert(更新或插入)。
经过尝试,无论我指定了insert还是upsert,它们的行为都相同。此外,如果我在文档中指定了replace,id元素就是必需的,但令人怀疑的是,实际上并不能指定id元素。
使用set-body元素来组合输入数据(JSON)。虽然在SQL Database中也出现过,但是使用Liquid模板语法进行描述。
删除
如果删除的话,将会遵循以下策略:(deleteUser)
<!-- deleteUser -->
<cosmosdb-data-source>
<!-- 接続設定は省略 -->
<delete-request>
<id>
@(context.GraphQL.Arguments["id"].Value<string>())
</id>
<partition-key>
@(context.GraphQL.Arguments["id"].Value<string>())
</partition-key>
</delete-request>
</cosmosdb-data-source>
请设置delete-request的要素。
与read-request相似,需要指定键(id、partition-key)。
API 测试
考试方法与SQL数据库版本相同。
给你个小礼物
翻页
在 Cosmos DB 中,您可以通过查询来获取多个数据,并且可以控制分页。
解析器策略
<!-- getUsers -->
<cosmosdb-data-source>
<!-- 接続設定は省略 -->
<query-request>
<sql-statement>
SELECT * FROM c
</sql-statement>
+ <paging>
+ <max-item-count>
+ @(context.GraphQL.Arguments["input"]["maxItemCount"]?.Value<string>())
+ </max-item-count>
+ <continuation-token>
+ @(context.GraphQL.Arguments["input"]["continuationToken"]?.Value<string>())
+ </continuation-token>
+ </paging>
</query-request>
</cosmosdb-data-source>
设置 paging 元素。
通过 max-item-count 元素指定每页的获取数量(默认为100)。
通过 continuation-token 元素指定用于确定下一页的令牌(如下所述)。
max-item-count 和 continuation-token 都可以使用策略表达式来描述。
只有当将max-item-count设置为字符串时,才会出现错误。
<max-item-count>
<!-- ↓はエラー -->
@(context.GraphQL.Arguments["input"]["maxItemCount"]?.Value<int>())
</max-item-count>
模式
Schema的更改如下所示。
type Query {
- getUser(id: ID!): User!
+ getUsers(input: GetUserInput!): UserList!
getUsers(): UserList!
}
type Mutation {
createUser(input: CreateUserInput!): User!
updateUser(input: UpdateUserInput!): User!
deleteUser(id: ID!): Boolean!
}
type User {
id: ID!
name: String!
age: Int!
}
type UserList {
items: [User!]!
hasNextPage: Boolean!
endCursor: String
}
+input GetUserInput {
+ maxItemCount: Int
+ continuationToken: String
+}
"・・・省略・・・"
执行结果
最初未指定max-item-count的情况下执行,总共获取了3件。

查看响应后,可以看到存在endCursor和hasNextPage两个属性。
接下来,我们尝试为max-item-count指定2。

结果只剩下2项了。此外,endCursor和hasNextPage的值也发生了变化。当总数量超过max-item-count时,hasNextPage将为true,并且endCursor会设置一个用于查找下一页的令牌。
好的,我们尝试使用上述的令牌来指定 continuation-token。

刚刚未能获取的剩余1个已经成功获取到了。
其他
在这里,您也可以像 SQL Database 版本一样自定义响应和指定可选参数的方法一样使用!
最后
在API管理和数据库的帮助下,我们成功地创建了一个GraphQL的API。
另外,虽然没有在这里介绍,但我们也可以在数据更新时调用存储过程进行验证。
还有其他一些未被介绍的功能,如果你感兴趣的话,可以试试玩!