GraphQL-从嵌套JSON对象获取所有字段

GraphQL-从嵌套JSON对象获取所有字段,graphql,Graphql,我正在将GraphQL包装器放在现有RESTAPI上,如中所述。我有一个产品的API端点,它有一个指向嵌套对象的属性: // API Response { entity_id: 1, nested_object: { key1: val1, key2: val2, ... } } // What I want { product(id: "1") { entityId nestedObject } } // What I don't

我正在将GraphQL包装器放在现有RESTAPI上,如中所述。我有一个产品的API端点,它有一个指向嵌套对象的属性:

// API Response
{
  entity_id: 1,
  nested_object: {
    key1: val1,
    key2: val2,
    ...
  }
}
// What I want
{
  product(id: "1") {
    entityId
    nestedObject
  }
}

// What I don't want
{
  product(id: "1") {
    entityId
    nestedObject {
      key1
      key2
      ...
    }
  }
}
是否可以定义模式,以便在不显式定义嵌套对象及其所有属性的情况下获取整个嵌套对象?我希望我的查询只指定我想要嵌套对象,而不需要指定我想要嵌套对象的所有属性:

// API Response
{
  entity_id: 1,
  nested_object: {
    key1: val1,
    key2: val2,
    ...
  }
}
// What I want
{
  product(id: "1") {
    entityId
    nestedObject
  }
}

// What I don't want
{
  product(id: "1") {
    entityId
    nestedObject {
      key1
      key2
      ...
    }
  }
}
我可以做第二个版本,但它需要很多额外的代码,包括创建
NestedObjectType
和指定所有嵌套属性。我还发现了如何自动获取所有密钥的列表,如下所示:

const ProductType = new GraphQLObjectType({
  ...

  fields: () => ({
    nestedObject: {
      type: new GraphQLList(GraphQLString),
      resolve: product => Object.keys(product.nested_object)
    }
  })
})
不过,我还没有找到一种自动返回整个对象的方法

我可以使用第二个版本,但它需要很多额外的代码,包括创建NestedObjectType和指定所有嵌套属性

做吧!那太好了。为了充分利用GraphQL的潜力,这是一条路要走

除了防止过度抓取之外,它还为您提供了许多其他好处,如类型验证,以及更可读和更可维护的代码,因为您的模式可以更全面地描述您的数据。你以后会感谢自己提前做了额外的工作

如果出于某种原因,您确实不想走这条路,并且完全理解其后果,那么可以使用
JSON.stringify
将嵌套对象编码为字符串


但就像我说的,我建议你不要

您可以尝试使用标量JSON类型。你可以找到更多

  • 标量JSON
    添加到模式定义中
  • {JSON:GraphQLJSON}
    添加到解析函数中
  • 在shema中使用JSON类型:
  • 查询的一个示例:
  • 结果是:
基本代码:


    const express = require("express");
    const graphqlHTTP = require("express-graphql");
    const { buildSchema } = require("graphql");
    const GraphQLJSON = require("graphql-type-json");

    const schema = buildSchema(`
      scalar JSON

      type Query {
        getObject: JSON
      }
    `);

    const root = {
      JSON: GraphQLJSON,

      getObject: () => {
        return {
          key1: "value1",
          key2: "value2",
          key3: "value3"
        };
      }
    };

    const app = express();
    app.use(
      "/graphql",
      graphqlHTTP({
        schema: schema,
        rootValue: root,
        graphiql: true
      })
    );
    app.listen(4000);
    console.log("Running a GraphQL API server at localhost:4000/graphql");


AFAIK,在不显式指定其字段的情况下提供整个嵌套对象目前在GraphQL中是不可行的。它有点违背GraphQL的原则,GraphQL的目标是只提供所需/请求的数据片段,而不是一次提供所有数据。你应该认真考虑使用GoCQL的动机。如果您关心移动数据带宽,它可能是一个不错的选择。感谢您的回复。我只是为了学习而玩弄它。我想可能是这样的。对我来说,这对于顶级查询是有意义的,但对于嵌套对象就没有这么多意义了。在这个组件中,我只想遍历嵌套对象中的所有内容——似乎如果在服务器上向该对象添加了一些内容,客户端就不必担心了。我想如果您使用GraphQL作为主api而不是包装现有的REST api,那么这个问题将更容易避免。“似乎如果在服务器上向该对象添加了某些内容,客户端就不必担心它了。”您是指基于推送的通知/更新(从服务器到客户端)?否,我的意思是更改代码-如果您在服务器上为对象添加了一个新的密钥,那么您似乎也不需要在客户端更新代码。客户端需要做的就是显示嵌套对象中的每个键值对,它不需要知道这些键值被调用了什么。目前,不在客户端进行修改就获取服务器端新引入的数据是不可行的。如果
nested_object
不再将嵌套对象作为值,那么您可以尝试一个丑陋的替代方法-将
nested_object
定义为字符串数组,其中第一个元素是键,下一个元素是其值,依此类推。这样,数组可以任意长,并且您的
嵌套_对象
在服务器端可以灵活地进行w.r.t.更改。

    const express = require("express");
    const graphqlHTTP = require("express-graphql");
    const { buildSchema } = require("graphql");
    const GraphQLJSON = require("graphql-type-json");

    const schema = buildSchema(`
      scalar JSON

      type Query {
        getObject: JSON
      }
    `);

    const root = {
      JSON: GraphQLJSON,

      getObject: () => {
        return {
          key1: "value1",
          key2: "value2",
          key3: "value3"
        };
      }
    };

    const app = express();
    app.use(
      "/graphql",
      graphqlHTTP({
        schema: schema,
        rootValue: root,
        graphiql: true
      })
    );
    app.listen(4000);
    console.log("Running a GraphQL API server at localhost:4000/graphql");