向GraphQL mutation发送含$ref的原始JSON的优雅实现方案问询
最优零改造方案:通过GraphQL变量传递JSON结构
你遇到的$ref校验报错是GraphQL查询文档的语法限制,仅作用于写在查询字符串内的输入对象字段名,通过查询变量传递的JSON内容完全不受该规则限制,不需要修改任何现有服务端代码,也不需要额外编解码操作:
- 按正常写法写GraphQL查询文档,不要把JSON内容内联到查询字符串中:
mutation MyMutation($input: MyInput!) { saveData(input: $input) { id } }
- 把带
$ref的完整JSON blob直接放在variables参数中即可:
{ "input": { "jsonField": { "$ref": "#/components/schemas/MySchema", "otherKey": "any value" } } }
该方案完全兼容你当前在用的JSON scalar,改造成本为0,是最推荐的实现方式。
备选兼容方案:自定义字符串转JSON的Scalar
如果你的业务场景必须要在查询文档内联传递JSON内容,可以自定义Scalar自动完成字符串到JSON对象的转换,彻底规避字段名校验:
- 服务端定义自定义Scalar:
public static final GraphQLScalarType RAW_JSON = GraphQLScalarType.newScalar() .name("RawJSON") .description("接收字符串形式的JSON blob,自动反序列化为对象") .coercing(new Coercing<Object, String>() { private final ObjectMapper mapper = new ObjectMapper(); @Override public String serialize(Object input) throws CoercingSerializeException { try { return mapper.writeValueAsString(input); } catch (JsonProcessingException e) { throw new CoercingSerializeException("JSON序列化失败", e); } } @Override public Object parseValue(Object input) throws CoercingParseValueException { if (input instanceof String) { try { return mapper.readValue((String) input, Object.class); } catch (JsonProcessingException e) { throw new CoercingParseValueException("JSON反序列化失败", e); } } return input; } @Override public Object parseLiteral(Object input) throws CoercingParseLiteralException { if (input instanceof StringValue) { try { return mapper.readValue(((StringValue) input).getValue(), Object.class); } catch (JsonProcessingException e) { throw new CoercingParseLiteralException("JSON反序列化失败", e); } } throw new CoercingParseLiteralException("RawJSON类型仅接收字符串输入"); } }) .build();
- 客户端传值时将完整JSON序列化为字符串传递即可:
mutation { saveData(input: {jsonField: "{\"$ref\": \"#/components/schemas/MySchema\", \"otherKey\": \"any value\"}"}) { id } }
该方案兼容性更强,适合跨端场景下客户端不支持变量传值的特殊情况。
内容的提问来源于stack exchange,提问作者Nebehr Gudahtt
相关产品推荐
相关产品推荐

