java - 如何使用片段检查 Java 中请求的 GraphQL 字段?
问题描述
我有一个类似这样的 GraphQL 查询:
query {
getPosts {
...PostFragment
}
}
fragment SpecificPostFragment on SpecificPost {
owner {
id
name
}
}
fragment PostFragment on Post {
id
object
... on SpecificPost {
...SpecificPostFragment
}
}
我想知道是否:
- 请求字段对象
- 请求字段所有者
我尝试应用这里写的内容: https ://www.graphql-java.com/documentation/v11/fieldselection/
但dataFetchingEnvironment.getSelectionSet().contains("XXX")
似乎不适用于片段。怎么做 ?
解决方案
我还没有找到任何内置的解决方案,所以我自己写了。这是我的代码
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import graphql.execution.MergedField;
import graphql.language.Field;
import graphql.language.FragmentDefinition;
import graphql.language.FragmentSpread;
import graphql.language.InlineFragment;
import graphql.language.SelectionSet;
import graphql.schema.DataFetchingEnvironment;
public class GraphQLUtil {
private static class PathElement {
private final String name;
private final String typeName;
public PathElement(String name, String typeName) {
this.name = name;
this.typeName = typeName;
}
public String getName() {
return name;
}
public String getTypeName() {
return typeName;
}
}
public static boolean containsIncludingFragments(DataFetchingEnvironment env, String path) {
Objects.requireNonNull(env, "The data fetching environment must not be null");
Objects.requireNonNull(path, "The field path must not be null");
List<PathElement> elts = Stream.of(path.split("/")).map(p -> {
String pt = p.trim();
if (pt.isEmpty()) {
throw new IllegalArgumentException("Empty path element found");
}
int sepIdx = pt.indexOf(":");
String name = pt;
String typeName = null;
if (sepIdx >= 0) {
typeName = pt.substring(0, sepIdx);
name = pt.substring(sepIdx + 1, pt.length());
}
return new PathElement(name, typeName);
}).collect(Collectors.toList());
if (elts.isEmpty()) {
return false;
}
MergedField mf = env.getMergedField();
return searchPathElement(env, elts, 0, mf.getSingleField().getSelectionSet(), null);
}
private static boolean searchPathElement(
DataFetchingEnvironment env,
List<PathElement> elts,
int eltIndex,
SelectionSet selectionSet,
String selectionTypeName) {
if (eltIndex >= elts.size()) {
return true;
}
PathElement currentElt = elts.get(eltIndex);
String currentName = currentElt.getName();
String currentTypeName = currentElt.getTypeName();
List<Field> fields = selectionSet.getSelectionsOfType(Field.class);
boolean found = false;
for (Field f : fields) {
if (f.getName().equals(currentName) && (currentTypeName == null
|| selectionTypeName == null
|| currentTypeName.equals(selectionTypeName))) {
found = searchPathElement(env, elts, eltIndex + 1, f.getSelectionSet(), null);
if (found) {
return true;
}
}
}
List<FragmentSpread> fragments = selectionSet.getSelectionsOfType(FragmentSpread.class);
for (FragmentSpread f : fragments) {
FragmentDefinition fDef = env.getFragmentsByName().get(f.getName());
found = searchPathElement(env, elts, eltIndex, fDef.getSelectionSet(), fDef.getTypeCondition().getName());
if (found) {
return true;
}
}
List<InlineFragment> inlineFragments = selectionSet.getSelectionsOfType(InlineFragment.class);
for (InlineFragment f : inlineFragments) {
found = searchPathElement(env, elts, eltIndex, f.getSelectionSet(), f.getTypeCondition().getName());
if (found) {
return true;
}
}
return false;
}
}
你这样称呼它:
DataFetchingEnvironment dataEnv = ... // If like me you use GraphQL SPQR, you can get it with io.leangen.graphql.execution.ResolutionEnvironment
boolean t1= GraphQLUtil.containsIncludingFragments(dataEnv, "id");
boolean t2 = GraphQLUtil.containsIncludingFragments(dataEnv, "owner/id");
boolean t3 = GraphQLUtil.containsIncludingFragments(dataEnv, "SpecificPost:owner/id"); // You may give the type of the field, if in some inheritance scenario, it is ambiguous
请注意,此解决方案不支持通配符(* 或?)。如果主查询包含多个条目(例如,同一查询中的 getPost + getPeople),我还没有对其进行测试,但在这种情况下可能不起作用。
推荐阅读
- python - 如何用破折号替换嵌套的短语列表?
- php - 展平多维数组 - PHP
- python-3.x - OSError: [Errno 99] 尝试绑定地址时出错,无法分配请求的地址
- mongodb - MongoDB 只使用一个线程
- python - 只需选择特定行中的列
- python - Shady 中的文本对齐控制
- javascript - 如何在具有背景图片的画布上添加“隐藏”网格?
- google-sheets-formula - 是否有一个冷的功能可以帮助我总结谷歌表格中一些重复值的时间间隔?
- laravel - 在 mac os catalina 中找不到 laravel 命令
- python - 为核密度估计选择带宽和空间。(为什么我的带宽不起作用?)