尝试在 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 数据库版本相同。

创建解析器

image.png
image.png

设置政策

网络设置(通用)

<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(更新或插入)。

2023/09/03时点
经过尝试,无论我指定了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件。

image.png

查看响应后,可以看到存在endCursor和hasNextPage两个属性。

接下来,我们尝试为max-item-count指定2。

image.png

结果只剩下2项了。此外,endCursor和hasNextPage的值也发生了变化。当总数量超过max-item-count时,hasNextPage将为true,并且endCursor会设置一个用于查找下一页的令牌。

好的,我们尝试使用上述的令牌来指定 continuation-token。

image.png

刚刚未能获取的剩余1个已经成功获取到了。

其他

在这里,您也可以像 SQL Database 版本一样自定义响应和指定可选参数的方法一样使用!

最后

在API管理和数据库的帮助下,我们成功地创建了一个GraphQL的API。
另外,虽然没有在这里介绍,但我们也可以在数据更新时调用存储过程进行验证。
还有其他一些未被介绍的功能,如果你感兴趣的话,可以试试玩!

bannerAds