将 2 个 REST 端点合并到单个 GraphQL 响应

Posted

技术标签:

【中文标题】将 2 个 REST 端点合并到单个 GraphQL 响应【英文标题】:Merging 2 REST endpoints to a single GraphQL response 【发布时间】: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
  
]

【问题讨论】:

【参考方案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 合并到一个通用模式中的问题?

以上是关于将 2 个 REST 端点合并到单个 GraphQL 响应的主要内容,如果未能解决你的问题,请参考以下文章

是否可以为单个 Spring Rest 端点自定义 ObjectMapper?

如何将日期,年,月的不同列合并/合并到单个列中

如何将2条提升曲线的图形合并到Python中的单个图形中

jHipster:仅将某些实体公开为REST端点

将 .p12 文件合并到单个密钥库中

将列表中的 n 个 DF 合并到单个 DataFrame - Scala