{"id":17933479,"url":"https://github.com/apache/sling-org-apache-sling-graphql-core","last_synced_at":"2025-03-24T06:32:39.697Z","repository":{"id":38315191,"uuid":"263040891","full_name":"apache/sling-org-apache-sling-graphql-core","owner":"apache","description":"Apache Sling GraphQL Core","archived":false,"fork":false,"pushed_at":"2024-10-28T17:38:58.000Z","size":496,"stargazers_count":9,"open_issues_count":2,"forks_count":12,"subscribers_count":26,"default_branch":"master","last_synced_at":"2025-03-17T12:21:51.731Z","etag":null,"topics":["graphql","java","sling"],"latest_commit_sha":null,"homepage":"https://sling.apache.org/","language":"Java","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/apache.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-11T12:49:58.000Z","updated_at":"2024-10-28T17:39:50.000Z","dependencies_parsed_at":"2022-07-16T05:16:34.870Z","dependency_job_id":"571ee9c9-a8d5-497e-99cf-226fe50d03ba","html_url":"https://github.com/apache/sling-org-apache-sling-graphql-core","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apache%2Fsling-org-apache-sling-graphql-core","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apache%2Fsling-org-apache-sling-graphql-core/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apache%2Fsling-org-apache-sling-graphql-core/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apache%2Fsling-org-apache-sling-graphql-core/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/apache","download_url":"https://codeload.github.com/apache/sling-org-apache-sling-graphql-core/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245223094,"owners_count":20580294,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["graphql","java","sling"],"created_at":"2024-10-28T21:40:19.497Z","updated_at":"2025-03-24T06:32:39.152Z","avatar_url":"https://github.com/apache.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Apache Sling](https://sling.apache.org/res/logos/sling.png)](https://sling.apache.org)\n\n\u0026#32;[![Build Status](https://ci-builds.apache.org/job/Sling/job/modules/job/sling-org-apache-sling-graphql-core/job/master/badge/icon)](https://ci-builds.apache.org/job/Sling/job/modules/job/sling-org-apache-sling-graphql-core/job/master/)\u0026#32;[![Test Status](https://img.shields.io/jenkins/tests.svg?jobUrl=https://ci-builds.apache.org/job/Sling/job/modules/job/sling-org-apache-sling-graphql-core/job/master/)](https://ci-builds.apache.org/job/Sling/job/modules/job/sling-org-apache-sling-graphql-core/job/master/test/?width=800\u0026height=600)\u0026#32;[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=apache_sling-org-apache-sling-graphql-core\u0026metric=coverage)](https://sonarcloud.io/dashboard?id=apache_sling-org-apache-sling-graphql-core)\u0026#32;[![Sonarcloud Status](https://sonarcloud.io/api/project_badges/measure?project=apache_sling-org-apache-sling-graphql-core\u0026metric=alert_status)](https://sonarcloud.io/dashboard?id=apache_sling-org-apache-sling-graphql-core)\u0026#32;[![JavaDoc](https://www.javadoc.io/badge/org.apache.sling/org.apache.sling.graphql.core.svg)](https://www.javadoc.io/doc/org.apache.sling/org.apache.sling.graphql.core)\u0026#32;[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.apache.sling/org.apache.sling.graphql.core/badge.svg)](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.apache.sling%22%20a%3A%22org.apache.sling.graphql.core%22)\u0026#32;[![graphql](https://sling.apache.org/badges/group-graphql.svg)](https://github.com/apache/sling-aggregator/blob/master/docs/groups/graphql.md) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)\n\nApache Sling GraphQL Core\n----\n\n_This module is one of several which provide [GraphQL support for Apache Sling](https://github.com/search?q=topic%3Asling+topic%3Agraphql+org%3Aapache\u0026type=Repositories)._\n\nThis module allows for running GraphQL queries in Sling, using dynamically built GraphQL schemas and\nOSGi services for data fetchers (aka \"resolvers\") which provide the data.\n\nTo take advantage of Sling's flexibility, it allows for running GraphQL queries in three different modes,\nusing client or server-side queries and optionally being bound to the current Sling Resource.\n\nServer-side queries are implemented as a Sling Script Engine.\n\nThe current version uses the [graphql-java](https://github.com/graphql-java/graphql-java) library but that's \nonly used internally. The corresponding OSGi bundles must be active in your Sling instance but there's no\nneed to use their APIs directly.\n\nThe [GraphQL sample website](https://github.com/apache/sling-samples/tree/master/org.apache.sling.graphql.samples.website)\nprovides usage examples and demonstrates using GraphQL queries (and Handlebars templates) on both the server and\nclient sides. It's getting a bit old and as of June 2021 doesn't demonstrate the latest features.\n\nAs usual, **the truth is in the tests**. If something's missing from this page you can probably find the details in\nthis module's [extensive test suite](./src/test).\n \n## Supported GraphQL endpoint styles\n\nThis module enables the following GraphQL \"styles\"\n\n  * The **traditional GraphQL endpoint** style, where the clients supply requests to a single URL. It is easy to define\n    multiple such endpoints with different settings, which can be useful to provide different \"views\" of your content.\n  * A **Resource-based GraphQL endpoints** style where every Sling Resource can be a GraphQL endpoint (using specific \n    request selectors and extensions) where queries are executed in the context of that Resource. This is an experimental\n    idea at this point but it's built into the design so doesn't require more efforts to support. That style supports both\n    server-side \"**prepared GraphQL queries**\" and the more traditional client-supplied queries.\n    \nThe GraphQL requests hit a Sling resource in all cases, there's no need for path-mounted servlets which are [not desirable](https://sling.apache.org/documentation/the-sling-engine/servlets.html#caveats-when-binding-servlets-by-path-1).\n\nSee also the _caching_ section later in this file.\n\n## Configuring the GraphQL Servlet\nHere's an excerpt from an OSGi feature model file which uses the GraphQL Servlet provided by this module\nto serve `.json` requests for resources which have the `samples/graphql` resource type:\n\n    \"configurations\":{\n      \"org.apache.sling.graphql.core.GraphQLServlet~default\" : {\n        \"sling.servlet.resourceTypes\" : \"samples/graphql\",\n        \"sling.servlet.extensions\": \"json\",\n        \"sling.servlet.methods\": [ \"GET\", \"POST\" ]\n      },\n      \"org.apache.sling.servlets.get.DefaultGetServlet\" : {\n        \"aliases\" : [ \"json:rawjson\" ]\n      },\n      \nThe `rawjson` selector is configured to provide Sling's default JSON output.\n\nSee the `GraphQLServlet` class for more info.\n\n## Resource-specific GraphQL schemas\n\nSchemas are provided by `SchemaProvider` services:\n\n```java\n@ProviderType\npublic interface SchemaProvider {\n  \n    /** Get a GraphQL Schema definition for the given resource and optional selectors\n     *\n     *  @param r The Resource to which the schema applies\n     *  @param selectors Optional set of Request Selectors that can influence the schema selection\n     *  @return a GraphQL schema that can be annotated to define the data fetchers to use, see\n     *      this module's documentation. Can return null if a schema cannot be provided, in which\n     *      case a different provider should be used.\n     *  @throws java.io.IOException if the schema cannot be retrieved\n     */\n    @Nullable\n    String getSchema(@NotNull Resource r, @Nullable String [] selectors) throws IOException;\n}\n```\n\nThe default provider makes an internal Sling request with for the current Resource with a `.GQLschema` extension.\n\nThis allows the Sling script/servlet resolution mechanism and its script engines to be used to generate \nschemas dynamically, taking request selectors into account.\n\nUnless you have specific needs not covered by this mechanism, there's no need to implement your\nown `SchemaProvider` services.\n\n## Built-in GraphQL Schema Directives\n\nSince version 0.0.10 of this module, a number of GraphQL schema directives are built-in to support specific\nfeatures. As of that version, the `@fetcher`, `@resolver` and `@connection` directives described below\ncan be used directly, without having to declare them explicitly in the schema with the `directive`\nstatement that was required before.\n\nDeclaring these directives explicitly is still supported for backwards compatibility with existing\nschemas, but not needed anymore.\n\n### SlingDataFetcher selection using the `@fetcher` directive\n\nThe following built-in `@fetcher` directive is defined by this module:\n\n```graphql\n    # This directive maps fields to our Sling data fetchers\n    directive @fetcher(\n        name : String!,\n        options : String = \"\",\n        source : String = \"\"\n    ) on FIELD_DEFINITION\n```\n\n\nIt allows for selecting a specific `SlingDataFetcher` service to return the appropriate data, as in the\nexamples below.\n\nFileds which do not have such a directive will be retrieved using the default data fetcher.\n\nHere are a few examples, the test code has more of them:\n\n```graphql\n    type Query {\n      withTestingSelector : TestData @fetcher(name:\"test/pipe\")\n    }\n\n    type TestData {\n      farenheit: Int @fetcher(name:\"test/pipe\" options:\"farenheit\")\n    }\n```\n\nThe names of those `SlingDataFetcher` services are in the form\n\n    \u003cnamespace\u003e/\u003cname\u003e\n\nThe `sling/` namespace is reserved for `SlingDataFetcher` services\nwhich have Java package names that start with `org.apache.sling`.\n\nThe `\u003coptions\u003e` and `\u003csource\u003e` arguments of the directive can be used by the\n`SlingDataFetcher` services to influence their behavior.\n\n### SlingTypeResolver selection using the `@resolver` directive\n\nThe following built-in `@resolver` directive is defined by this module:\n\n```graphql\n    # This directive maps the corresponding type resolver to a given Union\n    directive @resolver(\n        name: String!, \n        options: String = \"\", \n        source: String = \"\"\n    ) on UNION | INTERFACE\n```\n\nA `Union` or `Interface` type can provide a `@resolver` directive, to select a specific `SlingTypeResolver` service to return the appropriate GraphQL object type.\n\nHere's a simple example, the test code has more:\n\n    union TestUnion @resolver(name : \"test/resolver\", source : \"TestUnion\") = Type_1 | Type_2 | Type_3 | Type_4\n\nThe names of those `SlingTypeResolver` services are in the form\n\n    \u003cnamespace\u003e/\u003cname\u003e\n\nThe `sling/` namespace is reserved for `SlingTypeResolver` services\nwhich have Java package names that start with `org.apache.sling`.\n\nThe `\u003coptions\u003e` and `\u003csource\u003e` arguments of the directive can be used by the\n`SlingTypeResolver` services to influence their behavior.\n\n## Result Set Pagination using the `@connection` and `@fetcher` directives\n\nThis module implements support for the [Relay Cursor Connections](https://relay.dev/graphql/connections.htm)\nspecification, via the built-in `@connection` directive, coupled with a `@fetcher` directive. The built-in `@connection`\ndirective has the following definition:\n\n```graphql\n    directive @connection(\n      for: String!\n    ) on FIELD_DEFINITION\n```\n\nTo allow schemas to be ehanced with pagination support, like in this example:\n\n```graphql\n    type Query {\n        paginatedHumans (after : String, limit : Int) : HumanConnection @connection(for: \"Human\") @fetcher(name:\"humans/connection\")\n    }\n\n    type Human {\n        id: ID!\n        name: String!\n        address: String\n    }\n```\n\nUsing this directive as in the above example adds the following types to the schema to provide paginated\noutput that follows the Relay spec:\n\n```graphql\n    type PageInfo {\n        startCursor : String\n        endCursor : String\n        hasPreviousPage : Boolean\n        hasNextPage : Boolean\n    }\n\n    type HumanEdge {\n        cursor: String\n        node: Human\n    }\n\n    type HumanConnection {\n        edges : [HumanEdge]\n        pageInfo : PageInfo\n    }\n```\n\n### How to implement a SlingDataFetcher that provides a paginated result set\n\nThe [GenericConnection](./src/main/java/org/apache/sling/graphql/core/helpers/pagination/GenericConnection.java) class,\ntogether with the [`org.apache.sling.graphql.api.pagination`](./src/main/java/org/apache/sling/graphql/api/pagination) API\nprovide support for paginated results. With this utility class, you just need to supply an `Iterator` on your data, a\nfunction to generate a string that represents the cursor for a given object, and optional parameters to control the\npage start and length.\n\nThe [QueryDataFetcherComponent](./src/test/java/org/apache/sling/graphql/core/mocks/QueryDataFetcherComponent.java) provides a usage example: \n\n```java\n    @Override\n    public Object get(SlingDataFetcherEnvironment env) throws Exception {\n      // fake test data simulating a query\n      final List\u003cResource\u003e data = new ArrayList\u003c\u003e();\n      data.add(env.getCurrentResource());\n      data.add(env.getCurrentResource().getParent());\n      data.add(env.getCurrentResource().getParent().getParent());\n\n      // Define how to build a unique cursor that points to one of our data objects\n      final Function\u003cResource, String\u003e cursorStringProvider = r -\u003e r.getPath();\n\n      // return a GenericConnection that the library will introspect and serialize\n      return new GenericConnection.Builder\u003c\u003e(data.iterator(), cursorStringProvider)\n        .withLimit(5)\n        .build();\n    }\n```    \n\nThe above data fetcher code produces the following output, with the `GenericConnection` helper taking\ncare of the pagination logic and of generating the required data. This follows the\n[Relay Connections](https://relay.dev/graphql/connections.htm) specification, which some GraphQL clients\nshould support out of the box.\n\n```json\n    {\n      \"data\": {\n        \"oneSchemaQuery\": {\n          \"pageInfo\": {\n            \"startCursor\": \"L2NvbnRlbnQvZ3JhcGhxbC9vbmU=\",\n            \"endCursor\": \"L2NvbnRlbnQ=\",\n            \"hasPreviousPage\": false,\n            \"hasNextPage\": false\n          },\n          \"edges\": [\n            {\n              \"cursor\": \"L2NvbnRlbnQvZ3JhcGhxbC9vbmU=\",\n              \"node\": {\n                \"path\": \"/content/graphql/one\",\n                \"resourceType\": \"graphql/test/one\"\n              }\n            },\n            {\n              \"cursor\": \"L2NvbnRlbnQvZ3JhcGhxbA==\",\n              \"node\": {\n                \"path\": \"/content/graphql\",\n                \"resourceType\": \"graphql/test/root\"\n              }\n            },\n            {\n              \"cursor\": \"L2NvbnRlbnQ=\",\n              \"node\": {\n                \"path\": \"/content\",\n                \"resourceType\": \"sling:OrderedFolder\"\n              }\n            }\n          ]\n        }\n      }\n    }\n```\n\nUsage of this `GenericConnection` helper is optional, although recommended for ease of use and consistency. As long\nas the `SlingDataFetcher` provides a result that implements the [`org.apache.sling.graphql.api.pagination.Connection`](./src/main/java/org/apache/sling/graphql/api/pagination/Connection.java),\nthe output will be according to the Relay spec.\n\n## Lazy Loading of field values\n\nThe [org.apache.sling.graphql.helpers.lazyloading](src/main/java/org/apache/sling/graphql/helpers/lazyloading) package provides helpers\nfor lazy loading field values.\n\nUsing this pattern, for example:\n\n```java\n    public class ExpensiveObject {\n      private final LazyLoadingField\u003cString\u003e lazyName;\n\n      ExpensiveObject(String name) {\n        lazyName = new LazyLoadingField\u003c\u003e(() -\u003e {\n          // Not really expensive but that's the idea\n          return name.toUpperCase();\n        });\n      }\n\n      public String getExpensiveName() {\n        return lazyName.get();\n      }\n    }\n```\n\nThe `expensiveName` is only computed if its get method is called. This avoids executing expensive computations\nfor fields that are not used in the GraphQL result set.\n\nA similar helper is provided for Maps with lazy loaded values.\n\n## Caching: Persisted queries API\n\nNo matter how you decide to create your Sling GraphQL endpoints, you have the option to allow GraphQL clients to use persisted queries.\n\nAfter preparing a query with a POST request, it can be executed with a GET request that can be cached by HTTP caches or a CDN.\n\nThis is required as POST queries are usually not cached, and if using GET with the query as a parameter there's a concrete risk of \nthe parameter becoming too large for HTTP services and intermediates.\n\n### How to use persisted queries?\n\n1. An instance of the GraphQL servlet has to be configured; by default, the servlet will enable the persisted queries API on the\n `/persisted` request suffix; the value is configurable, via the `persistedQueries.suffix` parameter of the factory configuration.\n2. A client prepares a persisted query in advance by `POST`ing the query text to the endpoint where the GraphQL servlet is bound, plus the\n `/persisted` suffix.\n3. The servlet will respond with a `201 Created` status; the response's `Location` header will then instruct the client where it can then\n execute the persisted query, via a `GET` request.\n4. The responses for a `GET` requests to a persisted query will contain appropriate HTTP Cache headers, allowing front-end HTTP caches\n (e.g. CDNs) to cache the JSON responses. \n5. There's no guarantee on how long a persisted query is stored. A client that gets a `404` on a persisted query must be prepared to\n re`POST` the query, in order to store the prepared query again.\n\n#### Persisted Query Hash\n\nThe hash that's part of the `persisted` URL is computed on the POSTed GraphQL query by the\nactive `GraphQLCacheProvider` service. By default, this is the `SimpleGraphQLCacheProvider`\nwhich computes it as follows:\n\n```java\nMessageDigest digest = MessageDigest.getInstance(\"SHA-256\");\nbyte[] hash = digest.digest(query.getBytes(StandardCharsets.UTF_8));\n```\n    \nand encodes it in hex to build the persisted query's path.\n\nThis means that, if desired, an optimistic client can compute the hash itself and try a GET to\nthe `persisted/\u003chash\u003e` URL without doing a POST first. If the query already exists in the cache\nthis saves the POST request, and if not the client gets a 404 status and has to POST the query\nfirst.\n\n#### Example HTTP interactions with persisted queries enabled\n\n1. Storing a query\n    ```bash\n    curl -v 'http://localhost:8080/graphql.json/persisted' \\\n      -H 'Content-Type: application/json' \\\n      --data-binary '{\"query\":\"{\\n  navigation {\\n    search\\n    sections {\\n      path\\n      name\\n    }\\n  }\\n  article(withText: \\\"virtual\\\") {\\n    path\\n    title\\n    seeAlso {\\n      path\\n      title\\n      tags\\n    }\\n  }\\n}\\n\",\"variables\":null}' \\\n      --compressed\n    \u003e POST /graphql.json/persisted HTTP/1.1\n    \u003e Host: localhost:8080\n    \u003e User-Agent: curl/7.64.1\n    \u003e Accept: */*\n    \u003e Accept-Encoding: deflate, gzip\n    \u003e Content-Type: application/json\n    \u003e Content-Length: 236\n    \u003e\n    * upload completely sent off: 236 out of 236 bytes\n    \u003c HTTP/1.1 201 Created\n    \u003c Date: Mon, 31 Aug 2020 16:33:48 GMT\n    \u003c X-Content-Type-Options: nosniff\n    \u003c X-Frame-Options: SAMEORIGIN\n    \u003c Location: http://localhost:8080/graphql.json/persisted/e1ce2e205e1dfb3969627c6f417860cadab696e0e87b1c44de1438848661b62f.json\n    \u003c Content-Length: 0\n    ```\n2. Running a persisted query\n```bash\ncurl -v http://localhost:8080/graphql.json/persisted/e1ce2e205e1dfb3969627c6f417860cadab696e0e87b1c44de1438848661b62f.json\n\u003e GET /graphql.json/persisted/e1ce2e205e1dfb3969627c6f417860cadab696e0e87b1c44de1438848661b62f.json HTTP/1.1\n\u003e Host: localhost:8080\n\u003e User-Agent: curl/7.64.1\n\u003e Accept: */*\n\u003e\n\u003c HTTP/1.1 200 OK\n\u003c Date: Mon, 31 Aug 2020 16:35:18 GMT\n\u003c X-Content-Type-Options: nosniff\n\u003c X-Frame-Options: SAMEORIGIN\n\u003c Cache-Control: max-age=60\n\u003c Content-Type: application/json;charset=utf-8\n\u003c Transfer-Encoding: chunked\n\u003c\n\n{\n  \"data\": {\n    \"navigation\": {\n      \"search\": \"/content/search\",\n      \"sections\": [\n        {\n          \"path\": \"/content/articles/travel\",\n          \"name\": \"Travel\"\n        },\n        {\n          \"path\": \"/content/articles/music\",\n          \"name\": \"Music\"\n        }\n      ]\n    }\n    \"article\": [\n      {\n        \"path\": \"/content/articles/travel/precious-kunze-on-the-bandwidth-of-virtual-nobis-id-aka-usb\",\n        \"title\": \"Travel - Precious Kunze on the bandwidth of virtual 'nobis id' (aka USB)\",\n        \"seeAlso\": [\n          {\n            \"path\": \"/content/articles/travel/solon-davis-on-the-card-of-primary-reiciendis-omnis-aka-sql\",\n            \"title\": \"Travel - Solon Davis on the card of primary 'reiciendis omnis' (aka SQL)\",\n            \"tags\": [\n              \"bandwidth\",\n              \"protocol\"\n            ]\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n    \n## Planned Extensions / Wishlist\n\n### Selector-driven prepared queries (planned)\n\nDescribed in [SLING-10540](https://issues.apache.org/jira/browse/SLING-10540): prepared GraphQL queries hidden behind\nURL selectors, so that an HTTP GET request to `/content/mypage.A.full.json` executes the GraphQL query previously\nstored under the `A.full` name.\n\n### Schema Aggregator (planned)\n\nAn initial spec, without code so far, is available at\n[sling-whiteboard:sling-org-apache-sling-graphql-schema](https://github.com/apache/sling-whiteboard/tree/master/sling-org-apache-sling-graphql-schema)\nfor a _schema aggregator_ that allows OSGi bundles to contribute partial GraphQL schemas to an overall schema.\n\nThis will allow bundles to contribute specific sets of types to a schema, along with the code that implements their retrieval and other\noperations.\n\n### Object Query Service (whishlist)\n\nThe Object Query service runs queries against the Sling Resource tree and returns POJOs in\na way that's optimized for the GraphQL Core to consume.\n\nProbably something along those lines:\n\n    new Query(\n      \"\"\"\n      select Folder\n      from /tmp, /conf\n      where Folder.title contains 'sling'\n      and Folder.lastModified \u003c 1w\n      \"\"\")\n    .getIterator();\n\nwhich returns an `Iterator` optimized for this module's pagination features.\n\nThe objects that this Iterator supplies can be built from Sling Models, using the lazy loading helpers provided\nby this module. This would probably need an extension to Sling Models where the appropriate Model can be found\nfor a name like `Folder` in the above example. The Model class might be annotated in a way that allows it to\nsupply XPath query elements for expressions like `Folder.title`.\n\nThe Query might have additional options such as `withXpathGenerator`, `withObjectMapper` for edge cases\nwhere the built-in logic is not sufficient.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapache%2Fsling-org-apache-sling-graphql-core","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapache%2Fsling-org-apache-sling-graphql-core","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapache%2Fsling-org-apache-sling-graphql-core/lists"}