代码之家  ›  专栏  ›  技术社区  ›  Shlomi Schwartz

GraphQL-返回依赖于参数的计算类型

  •  12
  • Shlomi Schwartz  · 技术社区  · 7 年前

    概述

    在我的NodeJS服务器中,我实现了以下GraphQL模式:

    type Item {
      name: String,
      value: Float
    }
    
    
    type Query {
      items(names: [String]!): [Item]
    }
    

    然后,客户端查询将名称数组作为参数传递:

    {
      items(names: ["total","active"] ) {
        name
        value
      }
    }
    

    后端API查询mysql数据库中的“ 全部的 “和” 忙碌的 “字段(我的DB表上的列)并减少如下响应:

    [{"name":"total" , value:100} , {"name":"active" , value:50}]
    

    我希望我的graphQL API支持“比率”项,即:我希望发送以下查询:

    {
      items(names: ["ratio"] ) {
        name
        value
      }
    }
    

    {
      items(names: ["total","active","ratio"] ) {
        name
        value
      }
    }
    

    并返回 有效/总计 [{"name":"ratio" , value:0.5}] ). 处理这种情况的一般方法是什么?” 比率 “字段不同?

    它应该是我的模式中的一个新类型,还是应该在reducer中实现逻辑?

    2 回复  |  直到 7 年前
        1
  •  5
  •   Bless dontHaveName    7 年前

    乔的回答(附加 {"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
      }
    }
    

    比率 可以在分解器内计算。

    代码如下:

    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)))
    
        2
  •  2
  •   Joe Wearing    7 年前

    您可以设置解析器函数,使其使用第二个参数(参数)来查看名称“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);
    }
    

    我希望我正确理解了你的问题