GraphQL - return 计算类型取决于参数
GraphQL - return calculated type dependent on argument
概览(简体):
在我的 NodeJS 服务器中,我实现了以下 GraphQL 架构:
type Item {
name: String,
value: Float
}
type Query {
items(names: [String]!): [Item]
}
客户端查询然后传递一个名称数组作为参数:
{
items(names: ["total","active"] ) {
name
value
}
}
后端 API 查询 mysql 数据库,用于“total”和“active”字段(我的数据库中的列 table)并像这样减少响应:
[{"name":"total" , value:100} , {"name":"active" , value:50}]
我希望我的 graphQL API 支持 "ratio" 项,即:我想发送以下查询:
{
items(names: ["ratio"] ) {
name
value
}
}
或
{
items(names: ["total","active","ratio"] ) {
name
value
}
}
和returnactive/total作为那个新字段的计算结果([{"name":"ratio" , value:0.5}]
)。以不同方式处理“ratio”字段的通用方法是什么?
它应该是我模式中的新类型还是应该在 reducer 中实现逻辑?
您可以设置您的解析器函数,以便它使用第二个参数 - 参数 - 来查看名称 "ratio" 是否在您的名称数组中:
resolve: (root, { names }, context, fieldASTs) => {
let arrayOfItems;
// Contact DB, populate arrayOfItems with your total / active items
// if 'ratio' is within your name array argument, calculate it:
if (names.indexOf("ratio") > -1){
// Calculate ratio
arrayOfItems.push({ name: "ratio", value: calculatedRatio });
}
return(arrayOfItems);
}
希望我正确理解了你的问题
Joe 的回答(一旦从数据库中获取结果,就将 {"name":"ratio" , value:data.active/data.total}
附加到结果)将在不进行任何模式更改的情况下完成。
作为在 GraphQL 中执行此操作的替代方法或更优雅的方法,可以在类型本身中指定字段名称,而不是将它们作为参数传递。并通过编写解析器来计算 ratio
。
因此,GraphQL 架构将是:
Item {
total: Int,
active: Int,
ratio: Float
}
type Query {
items: [Item]
}
客户端指定字段:
{
items {
total
active
ratio
}
}
并且ratio
可以在解析器内部计算。
代码如下:
const express = require('express');
const graphqlHTTP = require('express-graphql');
const { graphql } = require('graphql');
const { makeExecutableSchema } = require('graphql-tools');
const getFieldNames = require('graphql-list-fields');
const typeDefs = `
type Item {
total: Int,
active: Int,
ratio: Float
}
type Query {
items: [Item]
}
`;
const resolvers = {
Query: {
items(obj, args, context, info) {
const fields = getFieldNames(info) // get the array of field names specified by the client
return context.db.getItems(fields)
}
},
Item: {
ratio: (obj) => obj.active / obj.total // resolver for finding ratio
}
};
const schema = makeExecutableSchema({ typeDefs, resolvers });
const db = {
getItems: (fields) => // table.select(fields)
[{total: 10, active: 5},{total: 5, active: 5},{total: 15, active: 5}] // dummy data
}
graphql(
schema,
`query{
items{
total,
active,
ratio
}
}`,
{}, // rootValue
{ db } // context
).then(data => console.log(JSON.stringify(data)))
概览(简体):
在我的 NodeJS 服务器中,我实现了以下 GraphQL 架构:
type Item {
name: String,
value: Float
}
type Query {
items(names: [String]!): [Item]
}
客户端查询然后传递一个名称数组作为参数:
{
items(names: ["total","active"] ) {
name
value
}
}
后端 API 查询 mysql 数据库,用于“total”和“active”字段(我的数据库中的列 table)并像这样减少响应:
[{"name":"total" , value:100} , {"name":"active" , value:50}]
我希望我的 graphQL API 支持 "ratio" 项,即:我想发送以下查询:
{
items(names: ["ratio"] ) {
name
value
}
}
或
{
items(names: ["total","active","ratio"] ) {
name
value
}
}
和returnactive/total作为那个新字段的计算结果([{"name":"ratio" , value:0.5}]
)。以不同方式处理“ratio”字段的通用方法是什么?
它应该是我模式中的新类型还是应该在 reducer 中实现逻辑?
您可以设置您的解析器函数,以便它使用第二个参数 - 参数 - 来查看名称 "ratio" 是否在您的名称数组中:
resolve: (root, { names }, context, fieldASTs) => {
let arrayOfItems;
// Contact DB, populate arrayOfItems with your total / active items
// if 'ratio' is within your name array argument, calculate it:
if (names.indexOf("ratio") > -1){
// Calculate ratio
arrayOfItems.push({ name: "ratio", value: calculatedRatio });
}
return(arrayOfItems);
}
希望我正确理解了你的问题
Joe 的回答(一旦从数据库中获取结果,就将 {"name":"ratio" , value:data.active/data.total}
附加到结果)将在不进行任何模式更改的情况下完成。
作为在 GraphQL 中执行此操作的替代方法或更优雅的方法,可以在类型本身中指定字段名称,而不是将它们作为参数传递。并通过编写解析器来计算 ratio
。
因此,GraphQL 架构将是:
Item {
total: Int,
active: Int,
ratio: Float
}
type Query {
items: [Item]
}
客户端指定字段:
{
items {
total
active
ratio
}
}
并且ratio
可以在解析器内部计算。
代码如下:
const express = require('express');
const graphqlHTTP = require('express-graphql');
const { graphql } = require('graphql');
const { makeExecutableSchema } = require('graphql-tools');
const getFieldNames = require('graphql-list-fields');
const typeDefs = `
type Item {
total: Int,
active: Int,
ratio: Float
}
type Query {
items: [Item]
}
`;
const resolvers = {
Query: {
items(obj, args, context, info) {
const fields = getFieldNames(info) // get the array of field names specified by the client
return context.db.getItems(fields)
}
},
Item: {
ratio: (obj) => obj.active / obj.total // resolver for finding ratio
}
};
const schema = makeExecutableSchema({ typeDefs, resolvers });
const db = {
getItems: (fields) => // table.select(fields)
[{total: 10, active: 5},{total: 5, active: 5},{total: 15, active: 5}] // dummy data
}
graphql(
schema,
`query{
items{
total,
active,
ratio
}
}`,
{}, // rootValue
{ db } // context
).then(data => console.log(JSON.stringify(data)))