【问题标题】:Merging 2 REST endpoints to a single GraphQL response将 2 个 REST 端点合并到单个 GraphQL 响应
【发布时间】:2018-04-13 17:03:32
【问题描述】:

graphQL 新手,我正在使用以下架构:

type Item {
    id: String,
    valueA: Float,
    valueB: Float
  }

  type Query {
    items(ids: [String]!): [Item]
  }

我的 API 可以针对每种类型(A 和 B)的单个请求返回多个项目,但不能同时返回两个项目,即:

类型 A 的 REST 请求:api/a/items?id=[1,2]
回应:

[
  {"id":1,"value":100},
  {"id":2,"value":30}
]

类型 B 的 REST 请求:api/b/items?id=[1,2]
回应:

[
  {"id":1,"value":50},
  {"id":2,"value":20}
]

我想将这 2 个 api 端点合并到一个 graphQL 响应中,如下所示:

[
  {
    id: "1",
    valueA: 100,
    valueB: 50
   },
   {
    id: "2",
    valueA: 30,
    valueB: 20
    }
 ]

问:如何编写一个解析器,为每种类型运行 单个 提取(获得多个项目响应)以确保在查询时不会触发不必要的提取缺少类型ie:

{items(ids:["1","2"]) {
  id
  valueA
}}

上面的例子应该只获取api/a/items?id=[1,2],graphQL 响应应该是:

[
  {
    id: "1",
    valueA: 100
  },
  {
    id: "2",
    valueA: 30
  }
]

【问题讨论】:

    标签: json rest api schema graphql


    【解决方案1】:

    所以我假设您使用 JavaScript 作为语言。在这种情况下,您需要的不是使用直接查询,而是使用片段

    所以查询会变成

    {
        items(ids:["1","2"]) {
           ...data
        }}
    
        fragment data on Item {
            id
          valueA
        }
    }
    

    接下来在解析器中,我们需要访问这些片段以找到属于片段一部分的字段,然后根据这些字段解析数据。下面是一个简单的nodejs文件,同样

    const util = require('util');
    
    var { graphql, buildSchema } = require('graphql');
    
    var schema = buildSchema(`
        type Item {
            id: String,
            valueA: Float,
            valueB: Float
        }
    
        type Query {
            items(ids: [String]!): [Item]
        }
    `);
    
    var root = { items: (source, args, root) => {
            var fields = root.fragments.data.selectionSet.selections.map(f => f.name.value);
            var ids = source["ids"];
    
            var data = ids.map(id => {return {id: id}});
            if (fields.indexOf("valueA") != -1)
            {
                // Query api/a/items?id=[ids]
                //append to data;
                console.log("calling API A")
                data[0]["valueA"] = 0.12;
                data[1]["valueA"] = 0.15;
            }
    
            if (fields.indexOf("valueB") != -1)
            {
                // Query api/b/items?id=[ids]
                //append to data;
                console.log("calling API B")
                data[0]["valueB"] = 0.10;
                data[1]["valueB"] = 0.11;
            }
            return data
    },
    };
    
    graphql(schema, `{items(ids:["1","2"]) {
           ...data
        }}
    
        fragment data on Item {
            id
          valueA
        }
    
        `, root).then((response) => {
        console.log(util.inspect(response, {showHidden: false, depth: null}));
    });
    

    如果我们运行它,输出是

    calling API A
    { data: 
       { items: [ { id: '1', valueA: 0.12 }, { id: '2', valueA: 0.15 } ] } }
    

    如果我们将查询更改为

    {
        items(ids:["1","2"]) {
           ...data
        }}
    
        fragment data on Item {
            id
            valueA
            valueB
        }
    }
    

    输出是

    calling API A
    calling API B
    { data: 
       { items: 
          [ { id: '1', valueA: 0.12, valueB: 0.1 },
            { id: '2', valueA: 0.15, valueB: 0.11 } ] } }
    

    因此,这演示了如何避免在不需要 API A/B 的字段时调用它们。完全按照你的要求

    【讨论】:

    • 像魅力一样工作:)
    • 另一个案例研究:如果 API 有不同的字段,我们如何解决将 2 个 API 合并到一个通用模式中的问题?
    猜你喜欢
    • 2019-07-26
    • 2020-12-29
    • 2017-02-05
    • 1970-01-01
    • 2016-11-30
    • 2018-02-19
    • 1970-01-01
    • 2018-05-22
    • 1970-01-01
    相关资源
    最近更新 更多