This sample provides a GraphQL query and command API that uses the sibling document-aggregator
module to output complete documents that aim to provide everything that's required to render a given Sling resource.
To start this, build the sibling modules with mvn clean install
in the parent folder of this one and then, in this folder, run
mvn clean install exec:java
Then open http://localhost:8080 - which might require logging in at http://localhost:8080/system/console first.
This should redirect you to a test GraphQL endpoint, currently http://localhost:8080/content.N.json - which is meant to be used by a GraphQL client.
Note that with that N selector, every resource is a GraphQL endpoint. This helps contextualize requests, querying a Folder
or Document
without a path parameter for example addresses the current Resource. I'm thinking of implementing selector-driven prepared GraphQL requests so that a GET request to /content.N.folders.json for example would execute the prepared folders query against that Resource.
The standard MAVEN_OPTS
environment variable can be used to setup debugging, as the above does not fork and starts the application with the Maven JVM.
Here are a few ideas in no specific order.
Uppercase selectors in these notes refer to the API planes concept, where the first uppercase selector addresses an “API plane” where specific functionality is available, usually with a specific GraphQL Schema. The term “plane” is similar to a geometric plane, it's not about flying metal tubes.
/content.P.folders.json
for example executes the ‘folders’ query that's been developed and stored from that developers plane. The P plane is for publishing, where HTTP GET requests return cacheable content based on stored queries.The overall idea is that accessing /content.N.json
with a GraphQL client should be sufficient for a developer to discover everything, via the commented GraphQL Schema provided there.
The test content uses com.adobe.aem.guides:aem-guides-wknd.ui.content.sample
which is MIT licensed. Minimal “fake” JCR nodetype definitions are used to allow this content to load, as we don't really care about the details of these node types besides their names.
This prototype is evolving, some of these examples might be out of date. See the Schema for the API plane N for possible Queries and Mutations.
# This one works at http://localhost:8080/content.N.json { folders(limit: 55, after: "L2NvbnRlbnQvYXJ0aWNsZXMvbXVzaWM=") { pageInfo { endCursor } edges { node { path header { resourceType title } } } } } # Works well at http://localhost:8080/content.N.json { folder { path header { parent resourceType resourceSuperType links { rel href } } } document(path:"/content/wknd") { path header { parent resourceType } body } } { folder(path: "/apps") { path header { parent } } } { document { path header { parent resourceType resourceSuperType title summary description links { href rel } } backstage { authoring publishing etc } body } } { documents(query: "//content/wknd/us/*/*") { edges { node { path header { parent resourceType resourceSuperType } body { source content } backstage { authoring { source content } } } } } } # we probably wouldn't use repoinit in this way - this # is just an example showing how to use a command pattern # via GraphQL mutations mutation { command( lang:"repoinit", input:""" # comments work here create path /open-for-all/ok """) { success output help } } # commands support free-form JSON data as input mutation { command(lang: "echo", input: {structuredJSONdata: { isSupported: true, for: "things like this", as: {json: "data"} } } ) { success output help } } mutation { command(lang: "echo", input: "Just a string, could also be an Integer, Float, Boolean, Array etc.") { success output help } } { documents(query: "//open-for-all/*") { edges { node { path } } } } { documents(lang: "sql2020", query: """ select * from nt:unstructured as R where [sling:resourceType] = 'wknd/components/carousel' and isdescendantnode(R, '/content/wknd/us/en') """) { pageInfo { endCursor } edges { node { path body { content } } } } } { document(path: "/content/articles") { path backstage { authoring { content } } } folder { path } folders(path: "/content/wknd/") { edges { node { path } } } documents(query: "//content/wknd/us/*/*") { edges { node { path header { parent resourceType resourceSuperType } body { source content } backstage { authoring { source content } } } } } }