{"id":14976000,"url":"https://github.com/intuit/gqlex","last_synced_at":"2026-03-06T20:31:49.098Z","repository":{"id":223931022,"uuid":"756661682","full_name":"intuit/gqlex","owner":"intuit","description":"eXtendGql is a powerful library that offers a unique path selection solution for GraphQL document, called gqlXPath; With advanced transformation abilities.","archived":false,"fork":false,"pushed_at":"2024-07-31T16:01:04.000Z","size":495,"stargazers_count":7,"open_issues_count":5,"forks_count":3,"subscribers_count":7,"default_branch":"main","last_synced_at":"2026-03-05T04:21:44.248Z","etag":null,"topics":["gqlxpath","graphql","graphql-api","graphql-java","graphql-js","graphql-schema","graphql-scraper","graphqlselection","gxpath","jsonpath","pathselection","xpath","xpath-expression"],"latest_commit_sha":null,"homepage":"https://dev.to/intuitdev/extend-graphql-gxpath-and-enhanced-transformer-12bf","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/intuit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-02-13T03:49:27.000Z","updated_at":"2025-11-05T20:25:22.000Z","dependencies_parsed_at":"2024-06-03T17:17:13.672Z","dependency_job_id":"ab7b37e4-8a94-47f0-bf81-6c0bfabe753a","html_url":"https://github.com/intuit/gqlex","commit_stats":null,"previous_names":["intuit/extendgql"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/intuit/gqlex","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/intuit%2Fgqlex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/intuit%2Fgqlex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/intuit%2Fgqlex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/intuit%2Fgqlex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/intuit","download_url":"https://codeload.github.com/intuit/gqlex/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/intuit%2Fgqlex/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30196173,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-06T19:07:06.838Z","status":"ssl_error","status_checked_at":"2026-03-06T18:57:34.882Z","response_time":250,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gqlxpath","graphql","graphql-api","graphql-java","graphql-js","graphql-schema","graphql-scraper","graphqlselection","gxpath","jsonpath","pathselection","xpath","xpath-expression"],"created_at":"2024-09-24T13:53:06.883Z","updated_at":"2026-03-06T20:31:49.051Z","avatar_url":"https://github.com/intuit.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# gqlex\n\n## Summary\ngqlex is a powerful library that offers a unique path selection solution for GraphQL, called gqleXPath. With this feature, developers can easily navigate the GraphQL data structure and select the information they need. In addition, the library includes an advanced transformation tool that allows for complex data manipulation. \n\n## Introduction\n\nI embarked on a project that demanded the manipulation of GraphQL documents and the querying of a target service using the manipulated GraphQL.\n\nTo achieve this, I realized that I needed to use some of the techniques that I had previously used to deal with JSON and XML. \n\nThe simplicity of JSONPath and xPath, along with complementary technologies like XSD, XSLT, and JavaScript, have contributed to the widespread use of XML and JSON over the years. These tools provide developers with extensive capabilities to select and manipulate JSON or XML documents.\n\nGraphQL and JSON are two separate schema files that serve different purposes and are not always used for externalizing or retrieving service data. Unlike JSON, which is primarily used for data storage and exchange, GraphQL documents are used only for sending queries and mutations to the GraphQL service and not for any other purpose, such as data formats like in JSON or XML.\n\nTo modify a GraphQL document, the following steps need to be followed:\n\n1. Traverse through the GraphQL document.\n2. Identify the relevant GraphQL node or nodes.\n3. Manipulate the GraphQL node or nodes as required.\n4. Create a new GraphQL document with the manipulated node or nodes.\n5. Pass the new GraphQL document to the GraphQL server to execute the query or mutation.\n\n_Let's exclude point (5) from our discussion, as it can be accomplished through multiple tools and code snippets._\n\nI found no open-source solution that could traverse the GraphQL document, select the relevant nodes, and manipulate the GraphQL document.\n\nThe article discusses the gqlex solution, which provides an intuitive solution for developers who need assistance with,\n1. Traverse through the GraphQL document\n2. Select nodes in the GraphQL document\n3. Manipulate selected nodes in the GraphQL document\n\nThe article will,\n- Describe the gqlex and abilities \n- Play with code\n- Elaborate on use cases\n\n## gqlex\n\n**gqlex** is a Java-based library.\n\nIn order to use the library, you should mvn clean install, \n\n_Soon, the artifact will be available via artifactory_\n\ngqlex leans on the [graphql-java](https://github.com/graphql-java/graphql-java) under MIT license, provide GraphQL java implementation, \n\nPOM file\n\n```\n\u003cdependency\u003e\n   \u003cgroupId\u003ecom.graphql-java\u003c/groupId\u003e\n   \u003cartifactId\u003egraphql-java\u003c/artifactId\u003e\n   \u003cversion\u003e20.4\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Traverse over GraphQL document\n\nEvery element in GraphQL, such as document, query, mutation, fragment, inline fragment, directive, etc., is derived from a node with unique attributes and behavior.\n\ngqlex uses the [observer pattern](https://en.wikipedia.org/wiki/Observer_pattern) pattern where the GraphQL document acts as a subject, traverses the entire document and notifies relevant observers on the node and context.\n\nThis observer pattern separates the traversal over the GraphQL document from the execution part that the observer consumer code would like to perform.\n\n## Selection of Node\n\nXML has [XPath](https://en.wikipedia.org/wiki/XPath).\nJSON has [JSONPath](https://github.com/json-path/JsonPath).\n\n\u003e And ... **GraphQL document has gqleXPath.**\n\ngqleXPath can be used to navigate through nodes in a GraphQL document.\ngqleXPath uses path expressions to select nodes or node on the GraphQL document.\n\n_Behind the scenes, the gqleXPath utilizes the traversal module \nand selects the node according to the required expression._\n\n### gqleXPath syntax\ngqleXPath uses path expressions to select nodes in GraphQL document. The node is selected by following a path or steps. \n\nThe most useful path expressions are listed below:\n\n| Expression | Description   |                                                                                                                                                                                                                                                                                                                    \n|---------|---------------------------------------|\n| //      | Path prefix: Select all nodes from the root node, and use a slash as a separator between path elements.                                                                                                                                                                                                                                |\n| /       | Path prefix: Select the first node from the root node and use a slash as a separator between path elements.  The range is not supported when the first node is selected.                                                                                                                                                                             |\n| {x:y}/  | Path prefix, Select path node(s), between a range of x path node and y path node (inclusion), use of slash as a separator between path elements. x and y are positive integers. All nodes are selected if no x and y are not set.                                                                                              |\n| {:y}//  | Path prefix, Select path node(s), between a range of first path node result to y, using a slash as a separator between path elements. x and y are positive integers. All nodes are selected if no x and y are not set.                                                                                                          |\n| {x:}/   | Path prefix, Select path node(a), between range of x path node result to the end of path nodes result, use slash as a separator between path elements. x and y are integers. if no x and y are not set, select all path nodes.                                                                                                   |\n| {:}//   | Path prefix, Select node(s) from the root node, use of slash as a separator between path elements.                                                                                                                                                                                                                                  | |\n| ... | Support of relative path **\"any\"** selection e.g. {x:y}//a/b/.../f \u003cbr\u003e  **any** can be set anywhere in the gqleXPath, except at the end of the gqleXPath, You can set many **any** as you request, this will help you while selecting node in large GraphQL structure, so you won't be required to mention/build the entire node structure. |\n\nThe library also provides an equivalent code named SyntaxPath that provides gqleXPath expression abilities use of code, mainly used by automation code.\n\n##Transformer\nThe transformer provides the ability to transform (Manipulate) **GraphQL** document simply.\nThe transformer uses the abilities provided by gqlex such as: gqleXPath, SyntaxPath etc.\n\nThe gqlex provides the following transform methods:\n1. Add Children - Add children node to selected **GraphQL** node or nodes\n2. Add Sibling - Add sibling node to selected **GraphQL** node or nodes\n3. Duplicate - Duplicate selected node by duplication number, multi nodes cannot be duplicated\n4. Remove Children  - Remove selected nodes or node\n5. Update name - Update selected nodes names or node names, for inline fragments, it will update the typeCondition name\n6. Update alias value - update field alias value and fragment spread alias value.\n\n## Code Play\n\n\u003e \nLet's start with traversal over the GrqphQL document\n\nStart with creating my observer, let's name it: StringBuilderObserver\n\nThe observer will append the GraphQL node to some StringBuilder.\n\nThis way, we achieve separation of concern: \n- Traverse over the GraphQL document nodes\n- Append node values with StringBuilder ....\n\n\n```java\npublic class StringBuilderObserver implements TraversalObserver {\n    private final List\u003cStringBuilderElem\u003e stringBuilderElems = new ArrayList\u003c\u003e();\n\n    private final boolean isIgnoreCollection = true;\n    @Override\n    public void updateNodeEntry(Node node, Node parentNode, Context context, ObserverAction observerAction) {\n\n        String  message = \"\";\n        DocumentElementType documentElementType = context.getDocumentElementType();\n        switch (documentElementType) {\n\n            case DOCUMENT:\n                message = MessageFormat.format(\"Node : {0} ||  Type : {1}\", \"Document\", documentElementType.name());\n\n                break;\n\n            case DIRECTIVE:\n                message = MessageFormat.format(\"Name : {0} ||  Type : {1}\", ((Directive) node).getName(), documentElementType.name());\n                break;\n            case FIELD:\n                Field field = (Field) node;\n                message = MessageFormat.format(\"Name : {0} || Alias : {1} ||  Type : {2}\",\n                        field.getName(),\n                        field.getAlias(),\n                        documentElementType.name());\n                break;\n            case OPERATION_DEFINITION:\n                message = MessageFormat.format(\"Name : {0} ||  Type : {1}\",\n                        ((OperationDefinition) node).getOperation().toString(), documentElementType.name());\n                break;\n            case INLINE_FRAGMENT:\n                message = MessageFormat.format(\"Node : {0} ||  Type : {1}\", \"InlineFragment\",\n                        documentElementType.name());\n\n                break;\n            case FRAGMENT_DEFINITION:\n                message = MessageFormat.format(\"Name : {0} ||  Type : {1}\",\n                        ((FragmentDefinition) node).getName(), documentElementType.name());\n\n                break;\n            case FRAGMENT_SPREAD:\n                message = MessageFormat.format(\"Node : {0} ||  Type : {1}\", ((FragmentSpread) node).getName(), documentElementType.name());\n                break;\n            case VARIABLE_DEFINITION:\n                message = MessageFormat.format(\"Name : {0} || Default Value : {1} ||  Type : {2}\",\n                        ((VariableDefinition) node).getName(), ((VariableDefinition) node).getDefaultValue(), documentElementType.name());\n\n                break;\n            case ARGUMENT:\n                message = MessageFormat.format(\"Name : {0} || Value : {1} ||  Type : {2}\",\n                        ((Argument) node).getName(),\n                        ((Argument) node).getValue(),\n                        documentElementType.name());\n                break;\n            case ARGUMENTS:\n                if(isIgnoreCollection) return;\n                message = MessageFormat.format(\"Node : {0} ||  Type : {1}\", \"Arguments\", documentElementType.name());\n                break;\n            case SELECTION_SET:\n                if(isIgnoreCollection) return;\n                message = MessageFormat.format(\"Node : {0} ||  Type : {1}\", \"SelectionSet\", documentElementType.name());\n                break;\n            case VARIABLE_DEFINITIONS:\n                if(isIgnoreCollection) return;\n                message = MessageFormat.format(\"Node : {0} ||  Type : {1}\", \"VariableDefinitions\", documentElementType.name());\n                break;\n            case DIRECTIVES:\n                if(isIgnoreCollection) return;\n                message = MessageFormat.format(\"Node : {0} ||  Type : {1}\", \"Directives\", documentElementType.name());\n                break;\n            case DEFINITIONS:\n                if(isIgnoreCollection) return;\n                message = MessageFormat.format(\"Node : {0} ||  Type : {1}\", \"Definitions\", documentElementType.name());\n\n                break;\n        }\n\n        if(Strings.isNullOrEmpty(message)){\n            return;\n        }\n\n        stringBuilderElems.add(new StringBuilderElem(message, context.getLevel()));\n\n        levels.add(context.getLevel());\n        //spaces++;\n    }\n    private final List\u003cInteger\u003e levels = new ArrayList\u003c\u003e();\n\n    public String getGqlBrowsedPrintedString() {\n        return getStringAs(true);\n    }\n\n    private String getStringAs(boolean isIdent) {\n        int j=0;\n        StringBuilder stringBuilder = new StringBuilder();\n        for (StringBuilderElem stringBuilderElem : stringBuilderElems) {\n            j++;\n            String spaceStr = \"\";\n            if( isIdent) {\n                for (int i = 0; i \u003c stringBuilderElem.getDepth(); i++) {\n                    spaceStr += \" \";\n                }\n                stringBuilder.append(spaceStr + stringBuilderElem.getName() + \"\\n\");\n            }else{\n                stringBuilder.append( stringBuilderElem.getName() + (j+1\u003cstringBuilderElems.size()? \" \" : \"\") );\n            }\n        }\n        return stringBuilder.toString();\n    }\n\n    public String getGqlBrowsedString(){\n        return getStringAs(false);\n    }\n\n//    int spaces = 0;\n    @Override\n    public void updateNodeExit( Node node,Node parentNode, Context context, ObserverAction observerAction) {\n    }\n}\n```\n\n```java\n\nGqlTraversal traversal = new GqlTraversal();\n\nStringBuilderObserver gqlStringBuilderObserver = new StringBuilderObserver();\n\ntraversal.getGqlTraversalObservable().addObserver(gqlStringBuilderObserver);\ntraversal.traverse(file);\n\nSystem.out.println( gqlStringBuilderObserver.getGqlBrowsedString());\n```\n\n\nAfter we saw how the traversal is working, lets digg with some example of **gqleXPath selection GraphQL nodes**\n\ngqleXPath define an expression language as defined above, in addition the expression language contains more terms to familiar with, _Element Name_ and types _abbreviations_.\nWhy its important, GraphQL document is more than structure that similar to JSON, GraphQL also provide a DSL that exposed by the GraphQL server and GraphQL language.\nthe types and the element name will assist the gqleXPath to select the exact node or nodes.\n\n\u003cu\u003eElement Names\u003c/u\u003e\n\n|element_name | Description                           |\n|--------------|---------------------------------------|\n| type=        | Select element by type abbreviate     |                                                                                                                                                                                                 |\n| name=        | Select element by name                |                                                                                                                                                                                                 |\n| alias=       | Select element by alias name          |\n\n\n\u003cu\u003eAvailable types and abbreviation\u003c/u\u003e\n\n| Type abbreviate | Description          |\n|-----------------|----------------------|\n| doc             | DOCUMENT             |\n| frag            | FRAGMENT_DEFINITION  |\n| direc           | DIRECTIVE            |\n| fld             | FIELD                |\n| mutation        | MUTATION_DEFINITION  |\n| query           | OPERATION_DEFINITION |\n| infrag          | INLINE_FRAGMENT      |\n| var             | VARIABLE_DEFINITION  |\n| arg             | ARGUMENT             | \n\n\n\u003e Let's practice the gqleXPath expression,\n\n__GraphQL Document__\n\nIn this document, we have 2 node named: 'name', but of different types: argument and field.\n\n```text\nquery {\n    Instrument(Name: \"1234\") {\n        Reference {\n            Name\n            title\n        }\n    }\n}\n```\n\n- Select all nodes (double slash) 'name' which is an argument type `//query/Instrument/name[type=arg]`\n\n- Select first node (single slash) 'name' which is an argument type `/query/Instrument/name[type=arg]`\n\n- `//query/.../name[type=arg]` Same as query `//query/Instrument/name[type=arg]`  \n      \n- Select of 'name' node which is field under Reference, reside under Instrument, reside under query `//query/Instrument/Reference/name`\n\n- `//query/Instrument/.../name` Same as `//query/Instrument/Reference/name`  \n    \n- `//.../name` Same as `//query/Instrument/Reference/name`\n\n\n__GraphQl Document__\n```text\nquery Hero($episode: Episode, $withFriends: Boolean!) {\n  hero(episode: $episode) {\n    name\n    friends @include(if: $withFriends) {\n      name\n    }\n    friends @include(if: $withFriends) {\n      name\n    }\n    friends @include(if: $withFriends) {\n      name\n    }\n    friends @include(if: $withFriends) {\n      name\n    }\n  }\n}\n```\n\n- Select all query nodes named hero `//query[name=hero]` \n\n- Select first query (single slash) node named hero `/query[name=hero]`     \n\n- Select all nodes named '_name_', reside under _friends_ node `//query[name=hero]/hero/friends/name` \n\n- Select all nodes named '_name_' within a range of index 0 and index 2 (inclusion), reside under friends node `{0:2}//query[name=hero]/hero/friends/name`   \n\n- Select node named '_name_', reside under any node, which reside under _hero_ node `/query[name=hero]/hero/.../name ` \n\n- Select _$withFriends_ variable reside directly under the root node named _hero_ `//query[name=hero]/withFriends[type=var]`\n\n- Select _include_ directive first node reside under friends, which reside under root query node named _hero_ `/query[name=hero]/hero/friends/include[type=direc] `             \n\n- Select the '_if_' argument node, reside under the _@include_ directive `//.../include[type=direc]/if[type=arg]`  \n\n- Select episode variable `//.../episode[type=var]`                                         \n\n\nHow to use gqleXPath in the code:\n\n```java\n\nSelectorFacade selectorFacade = new SelectorFacade();\n\nString queryString = Files.readString(file.toPath());\n\n// query {  Instrument(id: \"1234\") }\nGqlNodeContext select = selectorFacade.select(queryString, \"//query/Instrument /   Reference  /\");\n```\n\n__Use of SyntaxPath__\n\n```java\nString queryString = Files.readString(file.toPath());\n\nSyntaxBuilder gqlexBuilder = new SyntaxBuilder();\n\ngqlexBuilder.appendQuery();\ngqlexBuilder.appendField(\"Instrument\");\ngqlexBuilder.appendField(\"Reference\");\n\n// query {  Instrument(id: \"1234\") }\nGqlNodeContext select = selectorFacade.select(queryString, gqlexBuilder.build());\n```\n\n\nAnd finally we will dwell on an example that will illustrate the use of gqleXPath node selection GraphQL manipulation (AKA transform).\n\n\u003e Here a mutation GraphQL document\n\n```\nmutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {\n  createReview(episode: $ep, review: $review) {\n    stars\n    commentary\n    stars\n    commentary\n  }\n}\n```\n\nThe following java code will select and transform mutation document,\n\n```java\nString queryString = Files.readString(sourceFile.toPath());\n        \nTransformBuilder transformBuilder = new TransformBuilder();\ntransformBuilder.addChildrenNode(\"//mutation[name=CreateReviewForEpisode]/createReview/stars\",new Field(\"child_of_stars\"))\n        .addSiblingNode(\"//mutation[name=CreateReviewForEpisode]/createReview/stars\",new Field(\"sibling_of_stars\"))\n        .updateNodeName(\"//mutation[name=CreateReviewForEpisode]/createReview/stars\",\"star_new_name\")\n        .removeNode(\"//mutation[name=CreateReviewForEpisode]/createReview/commentary\")\n        .duplicateNode(\"//mutation[name=CreateReviewForEpisode]/createReview/sibling_of_stars\", 10);\n\nTransformExecutor transformExecutor = new TransformExecutor(transformBuilder);\n\nRawPayload rawPayload = new RawPayload();\nrawPayload.setQueryValue(queryString);\n\nRawPayload executeRawPayload = transformExecutor.execute(rawPayload);\n```\n\n\u003e **Description**:\n\n\u003e \n\u003cu\u003eadd new children node\u003c/u\u003e named: _child_of_stars_ under gqleXPath: `//mutation[name=CreateReviewForEpisode]/createReview/stars`\n\n\u003e \n\u003cu\u003eAdd new sibling node\u003c/u\u003e named: _sibling_of_stars_ under gqleXPath selected node: `//mutation[name=CreateReviewForEpisode]/createReview/stars`\n\n\u003e \n\u003cu\u003eSet new node name\u003c/u\u003e: _star_new_name_ value to the selected node by gqleXPath: \n\n`//mutation[name=CreateReviewForEpisode]/createReview/stars`\n \n\n\u003e \n\u003cu\u003eRemove selected node by gqleXPath\u003c/u\u003e `//mutation[name=CreateReviewForEpisode]/createReview/commentary`\n\n\n\u003e \n\u003cu\u003eDuplicate selected gqleXPath node 10 times\u003c/u\u003e `//mutation[name=CreateReviewForEpisode]/createReview/sibling_of_stars`\n\n\nUse TransformBuilder to build the transform plan, with selected node use of gqleXPath and the command to execute.\nThe transform plan is load to the TransformExecutor, with the GraphQL payload.\n\nThe execution will result in a new GraphQL document,\n\n```\nmutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {\n  createReview(episode: $ep, review: $review) {\n    sibling_of_stars\n    star_new_name {\n      child_of_stars\n    }\n    star_new_name {\n      child_of_stars\n    }\n    sibling_of_stars\n    sibling_of_stars\n    sibling_of_stars\n    sibling_of_stars\n    sibling_of_stars\n    sibling_of_stars\n    sibling_of_stars\n    sibling_of_stars\n    sibling_of_stars\n    sibling_of_stars\n  }\n}\n```\n\n\nLast example, will demonstrate the manipulation of directive from _include_ to _exclude_\n\nHere the query GraphQL document,\n\n```\nquery Hero($episode: Episode, $withFriends: Boolean!) {\n  hero(episode: $episode) {\n    name\n    friends **@include**(if: $withFriends) {\n      name\n    }\n  }\n}\n\n```\n\nHere the code:\n\n```java\n        String queryString = Files.readString(file.toPath());\n\n        // query {  Instrument(id: \"1234\") }\n        GqlNodeContext includeDirectiveNode = selectorFacade.selectSingle(queryString, \"//query[name=hero]/hero/friends/include[type=direc]\");\n\n        assertNotNull(includeDirectiveNode);\n\n        assertTrue(includeDirectiveNode.getType().equals(DocumentElementType.DIRECTIVE));\n        System.out.println(\"\\nBefore manipulation:\\n\\n\" + queryString);\n\n        // Node newNode = new Field(\"new_name\");\n        Node excludeDirectiveNode = TransformUtils.updateNodeName(includeDirectiveNode, \"exclude\");\n\n        String newGqlValue = gqlexWriter.writeToString(excludeDirectiveNode);\n\n        System.out.println(\"\\nAfter manipulation:\\n\\n\" + newGqlValue);\n\n        GqlNodeContext excludeUpdateNode = selectorFacade.selectSingle(newGqlValue, \"//query[name=hero]/hero/friends/exclude[type=direc]\");\n\n        assertTrue(excludeUpdateNode.getType().equals(DocumentElementType.DIRECTIVE));\n```\n\n```\n\nquery Hero($episode: Episode, $withFriends: Boolean!) {\n  hero(episode: $episode) {\n    name\n    friends @exclude(if: $withFriends) {\n      name\n    }\n  }\n}\n```\n\n## gqlex Use Cases\nThe gqlex can be used during base code while the developer required to enrich GraphQL document with more fields, while querying server for data, or during manipulation of data in server, so the code can articulate the relevant fields to manipulate in the service side.\nThe gqlex can also be utilize during integration or E2E testing, generating of synthetic GraphQL data, result with high velocity and managed solution.\n\nI elaborate the following use cases with more details:\n\n\u003e Synthetic GraphQL document creation\nTesting, mostly integration testing part will demands the ability to query GraphQL server with different queries and mutations.\n\nOf course, the developer can maintain large list of example files to send to the server or to find and replace the relevant string in GraphQL document, but it is a cumbersome solution, hard to maintain etc.\n\nThe ability to manipulate the query or the mutation with ease way, use configuration that enlist the plan [gqleXPath, Transform Commands and Argument to execute] and execute the planץ\n\n```\nConfiguration\n  Plan\n    steps\n      step 1\n         gqleXPath (String)\n         transform_commands\n           transform_command\n               command\n               argument_object_definition\n      step n\n         gqleXPath (String)\n         transform_commands\n           transform_command\n               command\n               argument_object_definition\n  origin_file_to_manipulate\n\nConfiguration config = read_configuration_plan(plan_file);\n\nconfig_verification()\n\nbuild_plan -\u003e ... use of TransformBuilder\n\nnew_graphql_document = execute_plan -\u003e ... use of TransformExecuter\n```\n \nVersatility and an extremely high ability to produce synthetic GraphQL data and a high ability to verify the integrity of a GraphQL service.\n\n\u003e Articulate GraphQL document on-the-fly\nSometime you required to build query or mutation upon configuration on the fly or upon business logic, and send it to the GraphQL server, The **gqlex** library will assist you while doing it, The **gqlex** library does not support creation (only manipulation) of the skeleton file and will not support (as for now).\nThe developer can create the skeleton GraphQL file, store the file in resource folder.\n_skeleton file, means file with structure but without field only._\nAnd with relevant plan use of syntaxPath we can assemble the gqleXPath and set the plan strategy on the fly, use of TransformBuilder.\nAnd then use of TransformExecutor to run the plan.\n\n\n\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fintuit%2Fgqlex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fintuit%2Fgqlex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fintuit%2Fgqlex/lists"}