close

Filter

loading table of contents...

Headless Server Developer Manual / Version 2406.1

Table Of Contents

4.16.1 Extension Points

CopyToContextParameter

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.


Search Results

Table Of Contents
warning

Your Internet Explorer is no longer supported.

Please use Mozilla Firefox, Google Chrome, or Microsoft Edge.