在 GraphQL Schema 中定义地图对象的最佳方式?
Posted
技术标签:
【中文标题】在 GraphQL Schema 中定义地图对象的最佳方式?【英文标题】:Best way to define a Map Object in GraphQL Schema? 【发布时间】:2021-08-22 16:30:26 【问题描述】:我尝试用对象数组映射一个键字符串。
我可以创建一个简单的对象,但我想在这些数组中轻松添加一个对象。地图对象非常适合执行此操作。
问题:我不知道如何为 GraphQL 定义类型映射 :'(
@ObjectType()
export class Inventaire
@Field()
_id: string;
@Field()
stocks: Map<string, Article[]>;
【问题讨论】:
Related 【参考方案1】:GraphQL 本身不支持 Map 类型。您可以为 Map 创建自己的标量或使用在 repo https://github.com/graphql-java/graphql-java-extended-scalars 中定义的现有 ObjectScalar
import graphql.Assert;
import graphql.language.ArrayValue;
import graphql.language.BooleanValue;
import graphql.language.EnumValue;
import graphql.language.FloatValue;
import graphql.language.IntValue;
import graphql.language.NullValue;
import graphql.language.ObjectValue;
import graphql.language.StringValue;
import graphql.language.Value;
import graphql.language.VariableReference;
import graphql.language.ObjectField;
import graphql.scalars.util.Kit;
import graphql.schema.Coercing;
import graphql.schema.CoercingParseLiteralException;
import graphql.schema.CoercingParseValueException;
import graphql.schema.CoercingSerializeException;
import graphql.schema.GraphQLScalarType;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
public class ObjectScalar extends GraphQLScalarType
public ObjectScalar()
this("Object", "An object scalar");
ObjectScalar(String name, String description)
super(name, description, new Coercing<Object, Object>()
public Object serialize(Object input) throws CoercingSerializeException
return input;
public Object parseValue(Object input) throws CoercingParseValueException
return input;
public Object parseLiteral(Object input) throws CoercingParseLiteralException
return this.parseLiteral(input, Collections.emptyMap());
public Object parseLiteral(Object input, Map<String, Object> variables)
throws CoercingParseLiteralException
if (!(input instanceof Value))
throw new CoercingParseLiteralException("Expected AST type 'StringValue' but" +
" was '" + Kit.typeName(input) + "'.");
else if (input instanceof NullValue)
return null;
else if (input instanceof FloatValue)
return ((FloatValue)input).getValue();
else if (input instanceof StringValue)
return ((StringValue)input).getValue();
else if (input instanceof IntValue)
return ((IntValue)input).getValue();
else if (input instanceof BooleanValue)
return ((BooleanValue)input).isValue();
else if (input instanceof EnumValue)
return ((EnumValue)input).getName();
else if (input instanceof VariableReference)
String varName = ((VariableReference)input).getName();
return variables.get(varName);
else
List values;
if (input instanceof ArrayValue)
values = ((ArrayValue)input).getValues();
return values.stream().map((v) ->
return this.parseLiteral(v, variables);
).collect(Collectors.toList());
else if (input instanceof ObjectValue)
values = ((ObjectValue)input).getObjectFields();
Map<String, Object> parsedValues = new LinkedHashMap();
values.forEach((fld) ->
Object parsedValue = this.parseLiteral(((ObjectField)fld).getValue(),
variables);
parsedValues.put(((ObjectField)fld).getName(), parsedValue);
);
return parsedValues;
else
return Assert.assertShouldNeverHappen("We have covered all Value types",
new Object[0]);
);
scalar Object
type Result
value : Object
【讨论】:
【参考方案2】:你可以使用这个包https://www.npmjs.com/package/graphql-type-json。
例子:
import makeExecutableSchema from 'graphql-tools';
import GraphQLJSON, GraphQLJSONObject from 'graphql-type-json';
const typeDefs = `
scalar JSON
scalar JSONObject
type MyType
myValue: JSON
myObject: JSONObject
# ...
`;
const resolvers =
JSON: GraphQLJSON,
JSONObject: GraphQLJSONObject,
;
export default makeExecutableSchema( typeDefs, resolvers );
【讨论】:
这个包被包含在graphql-scalars 的许可中,它包含了一堆其他有用的标量类型。【参考方案3】:GraphQL 是一种强类型语言,不提供任何开箱即用的 map 类型。 JSON blob 的键值对没有强大的架构,所以你不能有这样的东西:
key1: val1,
key2: val2,
key3: val3,
...
但是,您可以将 GraphQL Schema 定义为具有键值元组类型,然后定义您的属性以返回这些元组的数组。
type articleMapTuple
key: String
value: Article
type Inventaire
stocks: [articleMapTuple]
那么您的返回类型将如下所示:
data [
key: foo1,
value: some Article Object
,
key: foo2,
value: some Article Object
,
key: foo3,
value: some Article Object
,
]
【讨论】:
"GraphQL 是一种强类型语言,不提供任何开箱即用的地图类型。"就像没有提供地图类型的强类型语言一样?前半句和后半句之间没有联系。 也许我应该澄清一下 - GraphQL 是一种强类型语言 不提供任何开箱即用的地图类型。因此,您需要自己定义。 @gacharya 缺少 Map 类型仍然与强类型无关。映射对于表示本质上是映射的数据很有用。如果用于表示对象的属性,这是非常糟糕的,并且违背了打字的目的,但这不是地图的主要目标。 每个强类型语言都支持映射结构。 map的关键是每个key
都是同一个类型,每个value
都是同一个类型,所以Map也是一个强类型结构。以上是关于在 GraphQL Schema 中定义地图对象的最佳方式?的主要内容,如果未能解决你的问题,请参考以下文章
我无法在 typeDefs 中导入 schema.graphql 文件:找不到以下指针的任何 GraphQL 类型定义: