简体   繁体   中英

Access Selection Set of a graphQL query

Is it possible to access a GraphQL Selection Set from a query (String) in Java?

For instance from the string below:

"{
    data {
        title
        description
    }
}"

get a list of fields: ["data", "title", "description"]

If you mean to just extract the fields directly from a string, you can parse the query and recursively traverse the resulting document to collect the names.

You can parse the query this way:

Parser parser = new Parser();
Document document = parser.parseDocument(queryString);

The Document object is the query parsed into a tree structure. You can traverse it to extract what you need.

If you just need the selection set during field resolution (eg to see what sub-selections are requested so you optimize the fetching logic eg to fire a SELECT title, description FROM ... instead of a SELECT * FROM ... ) there's an easier way as DataFetchingEnvironment already provides access to the selection set:

DataFetchingFieldSelectionSet selectionSet = dataFetchingEnv.getSelectionSet();
Map<String, List<Field>> fieldsByName = selectionSet.get();

If you need to drill deeper than one level, you can use DataFetchingFieldSelectionSet.contains which accepts a glob pattern eg parent/*/grandChild and tells you whether such a field was requested.

You can also get the current Field from the DataFetchingEnvironment :

List<Field> getFields().get(0)

And from there you can extract the sub-selection for the current field. This last approach only makes sense if there are potentially conditional selections (ie the current field is an interface, so the selection might depend on the implementation eg ... on Impl { title } ).

This works for me, I have used the Parser in order to get the list of fields:

private static List<Field> parseGraphQLQuery(String query) {
    List<Field> fieldList = new ArrayList<Field>();

    Parser parser = new Parser();

    Document doc = parser.parseDocument(query);

    List<Definition> definitionList = doc.getDefinitions();
    definitionList.forEach( (item) -> {
        if (item instanceof OperationDefinition) {
            OperationDefinition operationDefinition = (OperationDefinition) item;
            SelectionSet selectionSet = operationDefinition.getSelectionSet();
            extractQueryElements(fieldList, selectionSet);
        }
    });

    return fieldList;
}

/**
 * Add fields to field name list
 * @param fieldNameList
 * @param selectionSet
 */
private static void extractQueryElements(List<Field> fieldNameList, SelectionSet selectionSet) {
    if (selectionSet != null && selectionSet.getSelections() != null) {
        selectionSet.getSelections().forEach( (selection) -> {
            if (selection instanceof Field) {
                Field field = (Field) selection;
                fieldNameList.add(field);
                extractQueryElements(fieldNameList, field.getSelectionSet());
            } 
        });
    }
}

I do know that OP did not tag spring . But for any spring users, who is landing on this page....You can directly get it injected by Spring in your controller methods.

@QueryMapping
public String books(DataFetchingFieldSelectionSet selectionSet){
  ....
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM