Headless Server Developer Manual / Version 2307
Table Of ContentsAn Adapter can be used to enhance domain model objects with
- Business logic from blueprint-base
- Aggregation, Recomposition
- Fallbacks
An Adapter is defined as Spring Bean and can be accessed from the GraphQL schema.
There are several predefined Adapters in the Headless Server, that can be accessed in the GraphQL schema.
For example, to access the settings of a content object, the SettingsAdapter
can be used.
The StructAdapter
provides access to values in structs.
The Adapter expects a name of the struct which is to be accessed and a list specifying the path including the property
to be found. This list shouldn't contain the name of the struct. Additionally, it is possible to provide a default value
which is used in case the struct value wasn't found.
type CMSettingsImpl implements CMSettings ... { settings(paths: [[String]]): JSON @fetch(from: "#paths == null ? #this.settings : @structAdapter.to(#root).getWrappedInStruct('settings',#paths, null)") }
Example 4.3. Retrieve a value from a struct with the StructAdapter
The SettingsAdapter
provides functionality to retrieve settings via the
SettingsService
from blueprint-base packages.
By doing so, it can find local and linked settings on content objects. The SettingsAdapter covers a specific case of
values in a Struct.
Inheritance of settings is not supported at the moment.
Although the schema demands a nested list structure as an argument, the underlying GraphQL framework accepts an incomplete list structure, even a single string. Graphql-Java enhances the missing lists automatically, which might lead to an unwanted or unexpected behaviour. Therefore it is recommended, to always specify an unambiguous, full list structure as demanded by the schema. This is true for the usages of the SettingsAdapter in the schema as well as for the StructAdapter, whenever a setting or a struct is retrieved by its path.
// a single string is interpreted as a single path, as expected. settings(paths: "commerce") // same behaviour as above settings(paths: ["commerce"]) settings(paths: [["commerce"]]) // two elements list: EACH entry is handled as an individual path! (potentially unexpected behaviour) settings(paths: ["commerce","endpoint"]) // recommended: fully qualified list structure specifying two settings paths settings(paths: [["commerce","endpoint"],["commerce","locale"]])
Example 4.4. Different ways to pass the paths parameter to the settings field from the GraphQL perspective
@Bean public SettingsAdapterFactory settingsAdapter(@Qualifier("settingsService") SettingsService settingsService) { return new SettingsAdapterFactory(settingsService); }
Example 4.5. Define SettingsAdapter as bean
type CMTeasableImpl implements CMTeasable ... { customSetting: String @fetch(from: "{!@settingsAdapter.to(#root).get({'customSetting'},'')}") }
Example 4.6. Retrieve settings with the SettingsAdapter
There are several Adapters available, for example:
-
structAdapter
Retrieve values from a Struct at a content object.
-
responsiveMediaAdapter
Retrieve the crops for a Picture.
-
mediaLinkListAdapter
Retrieve the media for a content object, for example, picture(s), video(s).
-
pageGridAdapter
Retrieve the pagegrid.
-
imageMapAdapter
Retrieve image maps.
-
navigationAdapter
Retrieve the navigation context.
DataFetchingEnvironment Support
Similar like a DataFetcher
, adapters can access the GraphQL DataFetchingEnvironment
.
The access is possible in two flavours. First, the DataFetchingEnvironment is available in the SpEL evaluation context
under the name #dataFetchingEnvironment
.
Second, if an adapter extends the class DataFetchingEnvironmentAware
, the current
DataFetchingEnvironment is automatically injected after(!) the instantiation of the adapter via its factory.
The DataFetchingEnvironment can be accessed via a getter. Additionally, DataFetchingEnvironmentAware offers
a convenience method to read any variable from the GraphQL context, e.g. the preview date.
Due to the fact, that the DataFetchingEnvironment is injected after the adapters instantiation, the factory method itself cannot access the DataFetchingEnvironment via the getter. If access is necessary during instantiation, the first approach via an explicit SpEL expression is inevitable.
# Example: Passing the DataFetchingEnvironment explicitly via SpEL. type CMNavigationImpl implements CMNavigation { ... grid: PageGrid @fetch(from: "@pageGridAdapter.to(#root,'placement', #dataFetchingEnvironment)") ... } # Example: Transparent access to the DataFetchingEnvironment. # - 'byPathAdapter' extends DataFetchingEnvironmentAware. # - DataFetchingEnvironment is injected after the factory method 'to()'! # - 'getPageByPath(#path)' accesses the DataFetchingEnvironment internally. type ContentRoot { ... pageByPath(path: String!): CMChannel @fetch(from: "@byPathAdapter.to().getPageByPath(#path)") ... }
Example 4.7. Accessing the DataFetchingEnvironment.
Automatic conversion of GraphQL input types to Java Objects
In most cases, scalar types like strings or integers are sufficient as call parameters for the execution method of an adapter. It is however also possible to use GraphQL input types as call parameters as well. Since GraphQL does not offer an out-of-the-box conversion of GraphQL input types to Java Objects, the given value of an input type will be a deserialized composition of collection classes, similar to a deserialized JSON string.
A Spring Converter offers the possibility to convert the values of an input type into a typed Java object, which in turn can the be used as input parameter of an adapter. If a suitable converter exists, the underlying Spring Expression Language will invoke it implicitly. A Converter simply has to be created as a regular SpringBean. It will then be automatically added to the EvaluationContext of the Spring Expression Language. See also Section 4.7, “Conversion Service”.