Headless Server Developer Manual / Version 2310
Table Of ContentsCopyToContextParameter
The extension point CopyToContextParameter offers the ability to declare additional parameters, for example, HTTP headers, which then will be added automatically to the GraphQL context during graphql queries.
public class SecurityTokenContextParameter implements CopyToContextParameter<String, String> { public static final String HEADER_NAME = "X-SECURITY-TOKEN"; public static final String NAME_IN_CONTEXT = "securityToken"; @Override public String getName() { return HEADER_NAME; } @Override public String getNameInContext() { return NAME_IN_CONTEXT; } @Override public ContextValueOrigin getValueOrigin() { return ContextValueOrigin.REQUEST_HEADER; } @Override public boolean previewOnly() { return false; } } // Bean factory in the plugin configuration class @Bean public SecurityTokenContextParameter securityTokenContextParameter() { return new SecurityTokenContextParameter(settingsService); }
Example 4.8. Example of a new http request header to be copied to the graphql context.
Implementations of this extension point can also be provided within CaasConfig
, using the qualifier
PluginSupport#QUALIFIER_CAAS_COPY_TO_CONTEXT_PARAMETER
at bean creation.
FilterPredicate
Implementations of FilterPredicate
are also fed to the ModelMapper during the server start.
They can also be provided within CaasConfig
, using the qualifier
PluginSupport#QUALIFIER_CAAS_FILTER_PREDICATE
at bean creation. See Section 4.6, “Filter Predicates” for details.
public class SecurityTokenFilterPredicate implements FilterPredicate<Object> { private static final String SERVER_SECRET_TOKEN = "secret-hash-set-by-environment"; public boolean test(DataFetchingEnvironment dataFetchingEnvironment, Object o) { String securityToken = (String) ((Map<String, Object>) dataFetchingEnvironment.getContext()).get(SecurityTokenContextParameter.NAME_IN_CONTEXT); return (securityToken != null && SERVER_SECRET_TOKEN.equalsIgnoreCase(securityToken)); } } // Bean factory in the plugin configuration class @Bean public SecurityTokenFilterPredicate securityTokenFilterPredicate( ContextVariableValueService contextVariableValueService ) { return new SecurityTokenFilterPredicate(contextVariableValueService); }
Example 4.9. Example of a filter predicate using the new context parameter.
PluginSchemaAdapterFactory
In conjunction with the plugin resource loading feature for GraphQL schema extensions, so called schema adapters can be invoked to resolve schema properties via the fetch directive using the Spring Expression Language (SpEL). While the out of the box schema adapters can be used without any problems, named schema adapters from within a plugin have to implement the extension point PluginSchemaAdapterFactory, in order to define the adapters name from within the plugin.
Note, that plugin schema adapters can only be used within the SpEL context of the GraphQL schema. For more information about adapters, please see Section 4.8, “Adapter”. An example can be found in the JavaDocs at PluginSchemaAdapterFactory.
CustomScalarType
The extension point CustomScalarType allows the definition of custom scalar types in plugins. Note, that to use a custom scalar type, you need to define it in the GraphQL schema as well as instantiate an instance of CustomScalarType as a Spring bean in the PluginConfiguration.
The custom scalar types of plugins are provided as a Spring bean by the Headless Server using the qualifier PluginSupport#QUALIFIER_PLUGIN_CUSTOM_SCALARS
CaasWiringFactory
This extension point allows to define additional WiringFactory
implementations in a plugin by
implementing CaasWiringFactory.
Implementations of this extension point are provided as a Spring bean using the qualifier PluginSupport#QUALIFIER_PLUGIN_WIRING_FACTORIES.
All WiringFactory implementations, which are not part of a plugin must be marked with the qualifier PluginSupport#QUALIFIER_CAAS_WIRING_FACTORIES in order to distinguish them from the predicates created inside of Headless Server and merge them with the ones implemented in plugins.
PluginSchemaGenerator
This extension point allows to define an alternative SchemaGenerator
by implementing the interface
PluginSchemaGenerator.
In case a plugin defines a PluginSchemaGenerator
, it replaces the default schema generator.
Only one schema generator may be active at a time. In case multiple plugins try to register its own PluginSchemaGenerator
,
it cannot be assured, which one will be active. The active schema generator is printed into the log during startup of the Headless Server.
LinkComposer
This extension point allows to define additional LinkComposer
implementations in a plugin by
implementing the interface
UriLinkComposer
for URI links or
GrapQLLinkComposer
for GraphQL links.
Implementations of this extension point can be accessed using the qualifier PluginSupport#QUALIFIER_PLUGIN_LINK_COMPOSERS_URI and PluginSupport#QUALIFIER_PLUGIN_LINK_COMPOSERS_GRAPHQL at bean creation.
The default implementations of LinkComposer are then merged with the ones implemented in plugins.
CustomFilterQuery
A CustomFilterQuery
provides the ability to add additional filter queries to the Solr query, using the customFilterQueries
parameter of the GraphQL search
query.
Implementations of this type are provided as a Spring bean via a Spring configuration class,
e.g. CaasConfig
or via the means of a plugin.
For details about the implementation please see Section 6.3, “Custom Filter Queries”.
SearchServiceProvider
All search related adapters are using an SPI (Service Provider Interface) architecture, which makes it very easy to implement and provide an alternative service provider. The corresponding service provider defines method signatures for all important aspects of a search, like query creation, parameter validation, execution and result transformation. The corresponding adapter then invokes these aspects but it only acts as kind of a runtime environment for the service provider, not implementing any relevant business logic itself.
The search related SPI extension points are providing default implementations for the latter three aspects, while the creation of the solr query is usually part of a custom implementation.
The regular search is based on the
SearchServiceProvider.
The provider is invoked by an instance of the
SearchAdapter.
The default service provider is implemented by
DefaultSearchServiceProvider.
Implementations of SearchServiceProvider
provided via a plugin will replace the DefaultSearchServiceProvider
.
FacetedSearchServiceProvider
The faceted search is based on the
FacetedSearchServiceProvider.
The provider is invoked by an instance of the
FacetedSearchAdapter.
The default service provider is implemented by
DefaultFacetedSearchServiceProvider.
Implementations of FacetedSearchServiceProvider
provided via a plugin will replace the DefaultFacetedSearchServiceProvider
.
SuggestionSearchServiceProvider
Search suggestions are based on the
SuggestionSearchServiceProvider.
The provider is invoked by an instance of the
SuggestionAdapter.
The default service provider is implemented by
DefaultSuggestionSearchServiceProvider.
Implementations of SuggestionSearchServiceProvider
provided via a plugin will replace the DefaultSuggestionSearchServiceProvider
.
public class CustomSuggestionSearchSPI extends SuggestionSearchServiceProvider { private final SolrQueryBuilder suggestionsSolrQueryBuilder; public CustomSuggestionSearchSPI(ContentRepository contentRepository, SolrQueryBuilder suggestionsSolrQueryBuilder) { super(contentRepository); this.suggestionsSolrQueryBuilder = suggestionsSolrQueryBuilder; } @Override public SolrQuery createSearchQuery(String searchExpression, Site site, List<String> docTypes, boolean includeSubTypes, Content siteRootDocument, DataFetchingEnvironment dataFetchingEnvironment, List<FilterQueryArg> customDynamicFilterQueries, List<FilterQueryArg> customStaticFilterQueries, Map<String, Function<List<String>, String>> filterQueryDefinitions) { List<String> filterQueries = new ArrayList<>(); ZonedDateTime viewDate = dataFetchingEnvironment .getGraphQlContext() .get(PluginSupport.CONTEXT_PARAMETER_NAME_PREVIEW_DATE); filterQueries.add( SearchQueryHelper.validFromPastToValueQuery( suggestionsSolrQueryBuilder.getValidFromFieldName(), viewDate)); filterQueries.add( SearchQueryHelper.validFromValueToFutureQuery( suggestionsSolrQueryBuilder.getValidToFieldName(), viewDate)); filterQueries.addAll( SearchHelper.getExpandedCustomFilterQueries( customStaticFilterQueries, customDynamicFilterQueries, filterQueryDefinitions)); return suggestionsSolrQueryBuilder.createSearchQuery( searchExpression, siteRootDocument, -1, -1, filterQueries, Collections.emptyMap(), false); } }
Example 4.10. Example of a custom SuggestionSearchServiceProvider.