Docs 菜单
Docs 主页
/ /
Atlas App Services
/ /

定义自定义解析程序

在此页面上

  • Overview
  • 步骤
  • 创建新的自定义解析程序
  • 定义解析器字段名称
  • 定义父类型
  • 定义输入类型
  • 定义有效负载类型
  • 定义解析程序函数
  • 保存并部署解析程序
  • 自定义解析程序示例
  • Scenario & Schemas
  • 自定义查询解析程序
  • 自定义更改
  • 计算的属性

您可以定义自定义解析程序,为您的应用程序使用案例扩展 GraphQL API。您可以通过自定义解析程序定义新的根级操作,这些操作比生成的查询更改解析程序更复杂或更具体。您还可以在生成的文档类型中添加新的计算字段,以便每次操作读取扩展类型的文档时动态计算结果。

1

在 App Services 用户界面中,单击导航侧边栏中的 GraphQL,然后选择 Custom Resolvers(自定义解析程序)标签页。

单击 Add a Custom Resolver 按钮,打开新自定义解析器的配置界面。

App Services 用户界面中的自定义解析程序屏幕
2

GraphQL Field Name(GraphQL 字段名称)输入中,为解析程序指定 App Services 名称。App Services 使用该名称在父类型中公开自定义解析程序,因此,该名称应以对使用 GraphQL API 的开发者有用的方式描述解析程序功能。

3

App Services 将每个自定义解析程序作为字段在父类型上公开。父类型可能是根级查询更改生成的文档类型

Parent Type(父类型)下拉菜单中,选择以下选项之一:

选项
说明
Query

解析程序是根级 query 操作:

例子

名为 myCustomQuery 的查询的自定义解析程序具有以下生成的模式:

type Query {
myCustomQuery: DefaultPayload
...
}
Mutation

解析程序是根级 mutation 操作:

例子

名为 myCustomMutation 的更改的自定义解析程序具有以下生成的模式:

type Mutation {
myCustomMutation: DefaultPayload
...
}
Document Type

解析程序是指定文档类型上的计算属性。返回文档类型的任何查询或更改也可以请求由该类型上的自定义解析程序定义的计算属性。

例子

Task 类型上定义名为 myCustomTaskProperty 的计算属性的自定义解析程序具有以下生成的模式:

type Task {
myCustomTaskProperty: DefaultPayload
...
}
4

自定义解析程序可以接受来自传入查询或更改的输入参数。您可以使用现有的生成的输入类型,或者专门为解析程序定义新的自定义输入类型。

如果您指定一种输入类型,则 App Services 将自定义解析程序的生成 GraphQL 模式定义中的 input 参数公开为接受指定输入类型的可选参数。如果未指定输入类型,则自定义解析程序不接受任何参数。

Input Type(父类型)下拉菜单中,选择以下选项之一:

选项
说明
None

解析程序不接受任何输入。

例子

名为 myCustomQuery 的自定义解析程序不接受输入,它具有以下生成的模式:

type Query {
myCustomQuery: DefaultPayload
...
}
Scalar

解析程序使用生成的 Graph QL 模式中的现有标量类型

在第二个下拉菜单输入中,选择单个标量或具有多个相同类型的标量的数组。

例子

名为 myCustomQuery 的自定义解析程序使用 Scalar Type 选项指定 DateTiem 输入类型,它具有以下生成的模式:

type Query {
myCustomQuery(input: DateTime): DefaultPayload
...
}
Existing Type

解析程序使用生成的 GraphQL 模式中的现有输入类型

在第二个下拉菜单输入中,选择单个输入对象或具有多个相同类型的输入对象的数组。

例子

名为 myCustomQuery 的自定义解析程序使用 Existing Type 选项指定 TaskInsertInput 输入类型,它具有以下生成的模式:

type Query {
myCustomQuery(input: TaskInsertInput): DefaultPayload
...
}
Custom Type

App Services 根据您定义的模式专门为解析器生成新的输入类型。该模式必须是至少包含一个属性的 object 和为生成的输入类型定义唯一名称的 title 字段。

自定义输入类型的自定义解析器配置。

例子

名为 myCustomQuery 的自定义解析程序使用 Custom Type 选项以及名为 MyCustomQueryInput 的输入类型,它具有以下生成的模式:

input MyCustomQueryInput {
someArgument: String;
}
type Query {
myCustomQuery(input: MyCustomQueryInput): DefaultPayload
...
}
5

所有 GraphQL 解析程序必须返回符合模式中的特定类型的有效负载。对于自定义解析程序,您可以使用现有的生成的文档类型,专门为解析程序定义新的自定义有效负载类型,或者使用默认有效负载。App Services 在自定义解析程序的生成 GraphQL 模式定义中包含指定的有效负载类型。

Payload Type(父类型)下拉菜单中,选择以下选项之一:

选项
说明
DefaultPayload

解析程序返回自动生成的 DefaultPayload 类型,该类型具有以下签名:

type DefaultPayload {
status: String!
}

无论解析程序函数的返回值如何,status 字段始终解析为 "complete"

{
status: "complete"
}

例子

名为 myCustomQuery 的自定义解析程序使用 DefaultPayload 选项,它具有以下生成的模式:

type Query {
myCustomQuery: DefaultPayload
...
}
Scalar

解析程序使用生成的 Graph QL 模式中的现有标量类型

在第二个下拉菜单输入中,选择单个标量或具有多个相同类型的标量的数组。

例子

名为 myCustomQuery 的自定义解析程序使用 Scalar Type 选项指定 DateTime 有效负载类型,它具有以下生成模式:

type Query {
myCustomQuery: DateTime
...
}
Existing Type

解析程序从生成的 GraphQL 模式中返回现有的文档类型

在第二个下拉菜单输入中,选择单个文档类型或具有多个相同类型的文档的数组。

例子

名为 myCustomQuery 的自定义解析程序使用 Existing Type 选项指定 TaskInsertInput 输入类型,它具有以下生成的模式:

名为 myCustomQuery 的自定义解析程序使用 Existing Type 选项指定 [Task] 有效负载类型,它具有以下生成模式:

type Query {
myCustomQuery: [Task]
...
}
Custom Type

App Services 根据您定义的模式,专门为解析程序生成新的有效负载类型。模式必须是至少包含一个属性的 object 和为生成的输入类型定义唯一名称的 title 字段。

定义新的自定义有效负载类型的自定义解析程序配置。

例子

名为 myCustomQuery 的自定义解析程序使用 Custom Type 选项以及名为 MyCustomQueryPayload 的有效负载类型,它具有以下生成的模式:

input MyCustomQueryPayload {
someValue: String;
}
type Query {
myCustomQuery: MyCustomQueryPayload
...
}
6

在用户调用自定义解析程序时,App Services 执行解析程序函数并返回结果,该结果必须符合解析程序的 Payload Type

如果适用,App Services 将操作中的任何输入数据传递给函数。如果解析程序是文档类型上的计算属性,则 App Services 将调用解析程序的特定文档传递给函数。

自定义解析器函数有两种可能的签名,具体取决于是否接受输入:

exports = function myCustomResolver(input, source) {
// The `input` parameter that contains any input data provided to the resolver.
// The type and shape of this object matches the resolver's input type.
const { someArgument } = input;
// If the resolver is a computed property, `source` is the parent document.
// Otherwise `source` is undefined.
const { _id, name } = source;
// The return value must conform to the resolver's configured payload type
return {
"someValue": "abc123",
};
}
exports = function myCustomResolver(source) {
// If the resolver is a computed property, `source` is the parent document.
// Otherwise `source` is undefined.
const { _id, name } = parent;
// The return value must conform to the resolver's configured payload type
return {
"someValue": "abc123",
};
}

要定义解析器函数,请单击 Function 下拉列表,然后选择现有函数或创建新函数。

7

在配置解析程序后,单击 Save(保存)并部署应用程序。在部署后,您可以通过 GraphQL API 调用自定义解析程序。

以一个假设的仪表盘为例,销售团队用它来显示特定时间段内的各种统计数据和其他绩效指标。仪表盘使用本节中的自定义解析器来处理一些特定用例。

解析程序都引用 Sale 文档,这些文档具有以下模式:

type Sale {
_id: ObjectId!
customer_id: String!
year: String!
month: String!
saleTotal: Float!
notes: [String]
}
{
"title": "Sale",
"bsonType": "object",
"required": ["_id", "customer_id", "year", "month", "saleTotal"],
"properties": {
"_id": { "bsonType": "objectId" },
"customer_id": { "bsonType": "string" },
"year": { "bsonType": "string" },
"month": { "bsonType": "string" },
"saleTotal": { "bsonType": "decimal" },
"notes": {
"bsonType": "array",
"items": { "bsonType": "string" }
}
}
}

销售团队的假设仪表盘使用自定义查询解析程序,该解析程序返回特定月份的聚合销售数据。

App Services 为解析程序的自定义输入和有效负载类型生成模式定义,并将解析程序添加到其父类型(根级 Query)中:

type Query {
averageSaleForMonth(input: AverageSaleForMonthInput): AverageSaleForMonthPayload
}
input AverageSalesForMonthInput {
month: String!;
year: String!;
}
type AverageSaleForMonthPayload {
month: String!;
year: String!;
averageSale: Float!;
}

解析器使用以下配置:

选项
说明
Parent Type
Query
GraphQL Field Name
averageSaleForMonth
Input Type

自定义类型: AverageSaleForMonthInput

{
"bsonType": "object",
"title": "AverageSaleForMonthInput",
"required": ["month", "year"],
"properties": {
"month": {
"bsonType": "string"
},
"year": {
"bsonType": "string"
}
}
}
input AverageSalesForMonthInput {
month: String!;
year: String!;
}
Payload Type

自定义类型: AverageSaleForMonthPayload

{
"bsonType": "object",
"title": "AverageSaleForMonthPayload",
"required": ["month", "year", "averageSale"],
"properties": {
"month": {
"bsonType": "string"
},
"year": {
"bsonType": "string"
},
"averageSale": {
"bsonType": "decimal"
}
}
}
type AverageSaleForMonthPayload {
month: String!;
year: String!;
averageSale: Float!;
}
Function
exports = async function averageSaleForMonth({ month, year }) {
const cluster = context.services.get("mongodb-atlas");
const sales = cluster.db("corp").collection("sales");
const averageSalePayload = await sales
.aggregate([
{ $match: { month: month, year: year } },
{
$group: {
_id: { month: "$month", year: "$year" },
averageSale: { $avg: "$saleTotal" },
}
},
{
$project: {
month: "$_id.month",
year: "$_id.year",
averageSale: 1
}
}
])
.next();
return averageSalePayload;
};

要调用该自定义查询,您可以使用以下操作和变量:

query GetAverageSaleForMonth($averageSaleInput: AverageSaleForMonthInput!) {
averageSaleForMonth(input: $averageSaleInput) {
month
year
averageSale
}
}
{
"variables": {
"averageSaleInput": { month: "March", year: "2020" }
}
}

销售团队的假设仪表盘使用自定义更改解析程序,该解析程序将字符串注释添加到由 _id 标识的特定 Sale 文档中。

App Services 为解析程序的自定义输入类型生成模式定义,并将解析程序添加到其父类型(根级 Mutation)中:

type Mutation {
addNoteToSale(input: AddNoteToSaleInput): Sale
}
input AddNoteToSaleInput {
sale_id: ObjectId!;
note: String!;
}

解析器使用以下配置:

选项
说明
Parent Type
Mutation
GraphQL Field Name
addNoteToSale
Input Type

自定义类型: AddNoteToSaleInput

{
"bsonType": "object",
"title": "AddNoteToSaleInput",
"required": ["sale_id", "note"],
"properties": {
"sale_id": {
"bsonType": "objectId"
},
"note": {
"bsonType": "string"
}
}
}
input AddNoteToSaleInput {
sale_id: ObjectId!;
note: String!;
}
Payload Type

现有的类型: Sale

type Sale {
_id: ObjectId!
customer_id: String!
year: String!
month: String!
saleTotal: Float!
notes: [String]
}
{
"title": "Sale",
"bsonType": "object",
"required": ["_id", "customer_id", "year", "month", "saleTotal"],
"properties": {
"_id": { "bsonType": "objectId" },
"customer_id": { "bsonType": "string" },
"year": { "bsonType": "string" },
"month": { "bsonType": "string" },
"saleTotal": { "bsonType": "decimal" },
"notes": {
"bsonType": "array",
"items": { "bsonType": "string" }
}
}
}
Function
exports = async function addNoteToSale({ sale_id, note }) {
const cluster = context.services.get("mongodb-atlas");
const sales = cluster.db("corp").collection("sales");
const sale = await sales.findOneAndUpdate(
{ _id: sale_id },
{ $push: { notes: note } },
{ returnNewDocument: true }
);
return sale;
}

要调用该自定义查询,您可以使用以下操作和变量:

mutation AddNoteToSale($addNoteToSaleInput: AddNoteToSaleInput) {
addNoteToSale(input: $addNoteToSaleInput) {
_id
customer_id
month
year
saleTotal
notes
}
}
{
"variables": {
"addNoteToSaleInput": {
"sale_id": "5f3c2779796615b661fcdc25",
"note": "This was such a great sale!"
}
}
}

销售团队的假设仪表盘使用自定义解析程序,该解析程序将一个新的计算属性添加到每个 Sale 文档中。在操作请求给定 Sale 的计算字段时,解析程序查询外部系统,并返回关联的客户提交的支持案例。

App Services 为解析程序的自定义有效负载类型生成模式定义,并将解析程序添加到其父类型 Sale 中:

type Sale {
_id: ObjectId!
customer_id: String!
year: String!
month: String!
saleTotal: Float!
notes: [String]
customerSupportCases: [CustomerSupportCase]
}
type CustomerSupportCase {
caseId: String!
description: String!
}

解析器使用以下配置:

选项
说明
Parent Type
Sale
GraphQL Field Name
customerSupportCases
Input Type
Payload Type

自定义类型: [CustomerSupportCase]

{
"bsonType": "array",
"items": {
"title": "CustomerSupportCase",
"bsonType": "object",
"required": ["caseId", "description"],
"properties": {
"caseId": { "bsonType": "string" },
"description": { "bsonType": "string" }
}
}
}
type CustomerSupportCase {
caseId: String!
description: String!
}
type Sale {
_id: ObjectId!
customer_id: String!
year: String!
month: String!
saleTotal: Float!
notes: [String]
customerSupportCases: [CustomerSupportCase]
}
Function
exports = async function customerSupportCases(sale) {
// Return a list of objects from some external system
const cases = await fetchCustomerSupportCases({
customerId: sale.customer_id
});
return cases;
};

要使用该自定义计算属性,您可以执行以下操作:

query GetSalesWithSupportCases {
sales {
_id
customer_id
year
month
saleTotal
notes
customerSupportCases {
caseId
description
}
}
}

后退

GraphQL 类型、解析程序和操作符