javascript 具有基于参数的动态字段的 GraphQL ObjectType
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/45842544/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
GraphQL ObjectType with dynamic fields based on arguments
提问by TJR
We are in the situation that the response of our GraphQL Query has to return some dynamic properties of an object. In our case we are not able to predefine all possible properties - so it has to be dynamic.
我们的 GraphQL 查询的响应必须返回对象的一些动态属性。在我们的例子中,我们无法预定义所有可能的属性 - 所以它必须是动态的。
As we think there are two options to solve it.
我们认为有两种选择可以解决它。
const MyType = new GraphQLObjectType({
name: 'SomeType',
fields: {
name: {
type: GraphQLString,
},
elements: {
/*
THIS is our special field which needs to return a dynamic object
*/
},
// ...
},
});
As you can see in the example code is element the property which has to return an object. A response when resolve this could be:
正如您在示例代码中所见,元素是必须返回对象的属性。解决此问题时的响应可能是:
{
name: 'some name',
elements: {
an_unkonwn_key: {
some_nested_field: {
some_other: true,
},
},
another_unknown_prop: 'foo',
},
}
1) Return a "Any-Object"
1)返回一个“任何对象”
We could just return any object - so GraphQL do not need to know which fields the Object has. When we tell GraphQL that the field is the type GraphQlObjectType it needs to define fields. Because of this it seems not to be possible to tell GraphQL that someone is just an Object.
我们可以只返回任何对象——因此 GraphQL 不需要知道对象具有哪些字段。当我们告诉 GraphQL 该字段是 GraphQlObjectType 类型时,它需要定义字段。因此,似乎不可能告诉 GraphQL 某人只是一个对象。
Fo this we have changed it like this:
为此,我们已将其更改如下:
elements: {
type: new GraphQLObjectType({ name: 'elements' });
},
2) We could define dynamic field properties because its in an function
2)我们可以定义动态字段属性,因为它在一个函数中
When we define fields as an function we could define our object dynamically. But the field function would need some information (in our case information which would be passed to elements) and we would need to access them to build the field object.
当我们将字段定义为函数时,我们可以动态定义我们的对象。但是 field 函数需要一些信息(在我们的例子中,信息将传递给元素),我们需要访问它们来构建 field 对象。
Example:
例子:
const MyType = new GraphQLObjectType({
name: 'SomeType',
fields: {
name: {
type: GraphQLString,
},
elements: {
type: new GraphQLObjectType({
name: 'elements',
fields: (argsFromElements) => {
// here we can now access keys from "args"
const fields = {};
argsFromElements.keys.forEach((key) => {
// some logic here ..
fields[someGeneratedProperty] = someGeneratedGraphQLType;
});
return fields;
},
}),
args: {
keys: {
type: new GraphQLList(GraphQLString),
},
},
},
// ...
},
});
This could work but the question would be if there is a way to pass the args and/or resolve object to the fields.
这可以工作,但问题是是否有办法将 args 和/或解析对象传递给字段。
QuestionSo our question is now: Which way would be recommended in our case in GraphQL and is solution 1 or 2 possible ? Maybe there is another solution ?
问题所以我们现在的问题是:在我们的 GraphQL 案例中推荐哪种方式,解决方案 1 或 2 是否可行?也许还有另一种解决方案?
EditSolution 1 would work when using the ScalarType. Example:
使用 ScalarType 时,编辑解决方案 1 将起作用。例子:
type: new GraphQLScalarType({
name: 'elements',
serialize(value) {
return value;
},
}),
I am not sure if this is a recommended way to solve our situation.
我不确定这是否是解决我们情况的推荐方法。
采纳答案by Daniel Rearden
Neither option is really viable:
这两种选择都不可行:
GraphQL is strongly typed. GraphQL.js doesn't support some kind of
anyfield, and all types defined in your schema must have fields defined. If you look in the docs,fieldsis a required -- if you try to leave it out, you'll hit an error.Args are used to resolve queries on a per-request basis. There's no way you can pass them back to your schema. You schema is supposed to be static.
GraphQL 是强类型的。GraphQL.js 不支持某种
any字段,并且您的架构中定义的所有类型都必须定义字段。如果您查看 docs,fields是必需的 - 如果您尝试将其省略,则会遇到错误。Args 用于基于每个请求解析查询。您无法将它们传递回您的架构。您的架构应该是静态的。
As you suggest, it's possible to accomplish what you're trying to do by rolling your own customer Scalar. I think a simpler solution would be to just use JSON -- you can import a custom scalar for it like this one. Then just have your elementsfield resolve to a JSON object or array containing the dynamic fields. You could also manipulate the JSON object inside the resolver based on arguments if necessary (if you wanted to limit the fields returned to a subset as defined in the args, for example).
正如您所建议的,可以通过滚动您自己的客户标量来完成您想要做的事情。我认为一个更简单的解决方案是只使用 JSON - 您可以像这样为它导入一个自定义标量。然后只需将您的elements字段解析为包含动态字段的 JSON 对象或数组。如有必要,您还可以根据参数操作解析器内的 JSON 对象(例如,如果您想将返回的字段限制为 args 中定义的子集)。
Word of warning:The issue with utilizing JSON, or any custom scalar that includes nested data, is that you're limiting the client's flexibility in requesting what it actually needs. It also results in less helpful errors on the client side -- I'd much rather be told that the field I requested doesn't exist or returned null when I make the requestthan to find out later down the line the JSON blob I got didn't include a field I expected it to.
警告词:使用 JSON 或任何包含嵌套数据的自定义标量的问题在于,您限制了客户端请求其实际需要的灵活性。它还导致客户端出现不太有用的错误——我宁愿被告知我请求的字段不存在或在我发出请求时返回 null ,而不是稍后找出我得到的 JSON blob没有包含我期望的字段。
回答by Point Networks
One more possible solution could be to declare any such dynamic object as a string. And then pass a stringified version of the object as value to that object from your resolver functions. And then eventually you can parse that string to JSON again to make it again an object on the client side.
另一种可能的解决方案是将任何此类动态对象声明为字符串。然后将对象的字符串化版本作为值从解析器函数传递给该对象。然后最终您可以再次将该字符串解析为 JSON,使其再次成为客户端的对象。
I'm not sure if its recommended way or not but I tried to make it work with this approach and it did work smoothly, so I'm sharing it here.
我不确定它是否是推荐的方式,但我尝试使用这种方法使其工作并且工作顺利,所以我在这里分享它。

