You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2021/07/12 16:42:00 UTC

[sling-whiteboard] branch master updated: SLING-10551 - sync README with current code

This is an automated email from the ASF dual-hosted git repository.

bdelacretaz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git


The following commit(s) were added to refs/heads/master by this push:
     new d0e9b04  SLING-10551 - sync README with current code
d0e9b04 is described below

commit d0e9b04a8e5c1427e2c829e44c906c6edc1db986
Author: Bertrand Delacretaz <bd...@apache.org>
AuthorDate: Mon Jul 12 18:38:25 2021 +0200

    SLING-10551 - sync README with current code
---
 sling-org-apache-sling-graphql-schema/README.md    | 131 ++++++++++++---------
 .../aggregator/it/SchemaAggregatorServletIT.java   |  10 +-
 2 files changed, 81 insertions(+), 60 deletions(-)

diff --git a/sling-org-apache-sling-graphql-schema/README.md b/sling-org-apache-sling-graphql-schema/README.md
index c363e46..5f30fcc 100644
--- a/sling-org-apache-sling-graphql-schema/README.md
+++ b/sling-org-apache-sling-graphql-schema/README.md
@@ -6,20 +6,17 @@ Apache Sling GraphQL Schema Aggregator
 This module ([SLING-10551](https://issues.apache.org/jira/browse/SLING-10551)) provides services to combine partial GraphQL
 schema ("partials") supplied by _provider bundles_.
 
-The partials are text files that use the GraphQL SDL (Schema Definition  Language) syntax and are
-provided as OSGi bundle resources. We cannot name them "fragments" as that has a different meaning
-in a GraphQL schema. They might include "front matter" a la Markdown for metadata.
+The partials are structured text files, supplied as OSGi bundle resources, that provide sections (like query,
+mutation, types sections) that are aggregated to build a GraphQL Schema using the SDL (Schema 
+Definition  Language) syntax.
 
 A GraphQL schema must contain one `Query` statement and can contain a most one `Mutation` statement,
-so partials cannot be assembled by just concatenating them. The schema assembler defines some simple 
-rules for how to write the partials so that they can be aggregated efficiently.
+so partials cannot be assembled by just concatenating them. The schema assembler defines a simple
+section-based syntax for the partials, so that they can be aggregated efficiently.
 
-This module also provides a `GraphQLSchemaServlet` that generates schemas by aggregating partials.
-The result can be used directly by the Sling GraphQL Core module, which makes an internal Sling request
-to get the schema. Multiple instances of that servlet can be configured, each with specific servlet
-selection properties (selectors, extension etc.) along with a set of tags used to select which partials
-are included in a specific schema. Or maybe one instance with a mapping of request selectors to schema
-aggregation parameters.
+This module also provides a `SchemaAggregatorServlet` that generates schemas by aggregating partials, by
+mapping request selectors to lists of partial names. The result can be used directly by the Sling GraphQL
+Core module, which makes an internal Sling request to get the schema.
 
 With this mechanism, an OSGi bundle can provide both a partial schema and the Sling data fetching and
 processing services that go with it. This allows a GraphQL "API plane" (usually defined by a specific
@@ -29,65 +26,83 @@ specific set of queries, mutations and types.
 ## Provider bundles
 
 To provide partials, a bundle sets a `Sling-GraphQL-Schema` header in its OSGi manifest, with a value that
-points to one or several paths where partials are found in the bundle resources.
+points to a path under which partials are found in the bundle resources.
 
-A partial is a text file with a `.graphql.partial.txt` extension that has the following structure:
+A partial is a text file with the structure described below. As usual, The Truth Is In The Tests, see
+the [example partial in the test sources](./src/test/resources/partials/example.partial.txt) for a
+reference that's guaranteed to be valid.
 
-**TODO this is out of date, see tests!**
+    # Example GraphQL partial schema
+    # Any text before the first section is ignored.
 
-    # Front matter, similar to Markdown, ends with four dashes on a line within the first 50 lines.
-    partial.name: Folders and commands
-    tags: folder, command, development, authoring
-    ----
-    
-    # The aggregated schema will include org.apache.sling.* values in comments, to provide
-    # information on the aggregation process and help troubleshoot it.
+    PARTIAL: Example GraphQL schema partial
+    The contents of the PARTIAL section are ignored, only its
+    description (the text follows the PARTIAL section name
+    above) is used.
 
-    # If a partial contains a Query and/or Mutation statement, the schema assembler uses their
-    # indentation to parse them without having to consider the full SDL syntax.
-    #
-    # These Query and Mutation keywords, along with their closing bracket, MUST NOT be indented,
-    # and everything inside them MUST be indented by at least one whitespace character.
+    PARTIAL is the only required section.
 
-    type Query {
-        """ 
-        Query a single Folder.
-        If not specified, the path defaults to the Resource which receives the query request.
-        """
-        folder(path: String) : Folder @fetcher(name:"samples/folder")
-    }
+    REQUIRE: base.scalars, base.schema
+    The description of the optional REQUIRE section is a
+    comma-separated list of partials which are required for this
+    one to be valid. The content of this section is ignored, only
+    its description is used to build that list.
 
-    type Mutation {
-        """ 
-        'lang' is the command language
-        'script' is the script to execute, in the language indicated by 'lang'
-        """  
-        command(lang: String, input: Object) : CommandResult @fetcher(name:"samples/command")
-    }
+    PROLOGUE:
+    The content of the optional PROLOGUE section is concatenated
+    in the aggregated schema, before all the other sections.
 
-    # There are no constraints on the rest of the schema, which the assembler simply concatenates
-    # after the Query and Mutation sections
-    type Folder {
-      path : ID!
-    }
+    QUERY:
+    The content of the optional QUERY sections of all partials
+    is aggregated in a `type QUERY {...}` section in the output.
 
-## Implementation notes
+    MUTATION:
+    Like for the QUERY section, the content of the optional
+    MUTATION sections of all partials is aggregated in
+    a `type MUTATION {...}` section in the output.
 
-TODO remove those once the module is implemented.
+    TYPES:
+    The content of the TYPES sections of all partials is
+    aggregated in the output, after all the other sections.
 
-We can use an [OSGi Extender Pattern](https://enroute.osgi.org/FAQ/400-patterns.html) to handle the
-provider bundles, similar to what we do for 
-[initial content loading](https://sling.apache.org/documentation/bundles/content-loading-jcr-contentloader.html)
-.
+## Partial names
 
-The assembler bundle can use a
-[BundleTracker](https://docs.osgi.org/javadoc/r4v42/org/osgi/util/tracker/BundleTracker.html)
-to detect the provider bundles based on their manifest header.
+The name of a partial, used in the selector mappings of the
+`SchemaAggregatorServlet`, is defined by its filename in the
+bundle resources, omitting the file extension. A partial
+found under `/path-set-by-the-bundle-header/this.is.txt` in its bundle is named
+`this.is` . Partial names must be unique system-wide, so it's
+good to use some form of namespacing or agreed upon naming
+convention for them.
 
-It can use logic similar to the jcr content loader module to load the partial schema text files:
+## SchemaAggregatorServlet configuration
+Here's a configuration example from the test code.
 
-* https://github.com/apache/sling-org-apache-sling-jcr-contentloader/blob/master/src/main/java/org/apache/sling/jcr/contentloader/PathEntry.java
-* Bundle.getEntryPaths to enumerate file resources in the bundle
+    // Configure the org.apache.sling.graphql.schema.aggregator.SchemaAggregatorServlet
+    factoryConfiguration(AGGREGATOR_SERVLET_CONFIG_PID)
+        .put("sling.servlet.resourceTypes", "sling/servlet/default")
 
-On our dev list, Radu suggests creating an OSGi a capability in o.a.s.graphql.schema that the bundles which provide schema extensions require, in order to create the wiring in between the bundles. This allows a limited number of bundles to trigger the BundleTracker, creating a weak contract.
+        // The extension must be the one used by the GraphQLServlet to retrieve schemas
+        // which by default is 'GQLschema'
+        .put("sling.servlet.extensions", GQL_SCHEMA_EXT)
 
+        // The GraphQLServlet uses an internal GET request for the schema
+        .put("sling.servlet.methods", new String[] { "GET" })
+
+        // Several selectors can be configured to setup API planes, each with their own GraphQL schema
+        .put("sling.servlet.selectors", new String[] { "X", "Y" })
+
+        // This mapping defines which partials to use to build the schema for each selector
+        // The lists can use either the exact names of partials, or (Java flavored) regular expressions on
+        // their names, identified by a starting an ending slash.
+        .put("selectors.to.partials.mapping", new String[] { "X:firstA,secondB", "Y:secondA,firstB,/second.*/" })
+
+## TODO / wishlist
+The REQUIRES section of partial should be translated to OSGi capabilities, to be able to detect
+missing requirements at system assembly time or using the
+[Feature Model Analyser](https://github.com/apache/sling-org-apache-sling-feature-analyser).
+
+We'll probably need a utility to aggregate schemas for automated tests, to allow test code
+to include required schema partials.
+
+Caching is probably not needed in this module, as the GraphQL Core caches compiled schemas.
diff --git a/sling-org-apache-sling-graphql-schema/src/test/java/org/apache/sling/graphql/schema/aggregator/it/SchemaAggregatorServletIT.java b/sling-org-apache-sling-graphql-schema/src/test/java/org/apache/sling/graphql/schema/aggregator/it/SchemaAggregatorServletIT.java
index fe4cb6b..e3fb2e3 100644
--- a/sling-org-apache-sling-graphql-schema/src/test/java/org/apache/sling/graphql/schema/aggregator/it/SchemaAggregatorServletIT.java
+++ b/sling-org-apache-sling-graphql-schema/src/test/java/org/apache/sling/graphql/schema/aggregator/it/SchemaAggregatorServletIT.java
@@ -44,12 +44,18 @@ public class SchemaAggregatorServletIT extends SchemaAggregatorTestSupport {
             U.tinyProviderBundle("firstProvider", "firstA", "firstB","secondN"),
             U.tinyProviderBundle("secondProvider", "secondA", "secondB","secondOther"),
 
-            // The aggregator servlet is disabled by default
+            // Configure the org.apache.sling.graphql.schema.aggregator.SchemaAggregatorServlet
             factoryConfiguration(AGGREGATOR_SERVLET_CONFIG_PID)
                 .put("sling.servlet.resourceTypes", "sling/servlet/default")
+                // The extension must be the one used by the GraphQLServlet to retrieve schemas
                 .put("sling.servlet.extensions", GQL_SCHEMA_EXT)
-                .put("sling.servlet.selectors", new String[] { "X", "Y", "nomappings" })
+                // The GraphQLServlet uses an internal GET request for the schema
                 .put("sling.servlet.methods", new String[] { "GET" })
+                // Several selectors can be configured to setup API planes, each with their own GraphQL schema
+                .put("sling.servlet.selectors", new String[] { "X", "Y", "nomappings" })
+                // This mapping defines which partials to use to build the schema for each selector
+                // The lists can use either the exact names of partials, or (Java flavored) regular expressions on
+                // their names, identified by a starting an ending slash.
                 .put("selectors.to.partials.mapping", new String[] { "X:firstA,secondB", "Y:secondA,firstB,/second.*/" })
                 .asOption(),
         };