Version 5 supported

Extending the schema

Adding a custom model
Add a new class-backed type beyond DataObject
Adding a custom operation
Add a new operation for model types
Adding middleware
Add middleware to to extend query execution
The global schema
How to push modifications to every schema in the project

Adding middleware

Middleware is any piece of functionality that is interpolated into a larger process. A key feature of middleware is that it can be used with other middlewares in sequence and not have to worry about the order of execution.

In silverstripe/graphql, middleware is used for query execution, but could ostensibly be used elsewhere too if the API ever accomodates such an expansion.

The middleware API in the silverstripe/graphql module is separate from other common middleware APIs in Silverstripe CMS, such as HTTPMiddleware. The two are not interchangable.

The signature for middleware (defined in QueryMiddleware) looks like this:

use GraphQL\Type\Schema;

public abstract function process(Schema $schema, string $query, array $context, array $vars, callable $next);

The return value should be ExecutionResult or an array.

  • $schema: The underlying Schema object. Useful to inspect whether types are defined in a schema.
  • $query: The raw query string.
  • $context: An arbitrary array which holds information shared between resolvers. Use implementors of ContextProvider to get and set data, rather than relying on the array keys directly.
  • $vars: An array of (optional) Query Variables.
  • $next: A callable referring to the next middleware in the chain

Let's write a simple middleware that logs our queries as they come in.

namespace App\GraphQL\Middleware;

use GraphQL\Type\Schema;
use SilverStripe\GraphQL\Middleware\QueryMiddleware;
use SilverStripe\GraphQL\QueryHandler\UserContextProvider;
// ...

class LoggingMiddleware implements QueryMiddleware
{
    public function process(Schema $schema, string $query, array $context, array $vars, callable $next)
    {
        $member = UserContextProvider::get($context);

        Injector::inst()->get(LoggerInterface::class)
            ->info(sprintf(
                'Query executed: %s by %s',
                $query,
                $member ? $member->Title : '<anonymous>';
            ));

        // Hand off execution to the next middleware
        return $next($schema, $query, $context, $vars);
    }
}

Now we can register the middleware with our query handler:

SilverStripe\Core\Injector\Injector:
  SilverStripe\GraphQL\QueryHandler\QueryHandlerInterface.default:
    class: SilverStripe\GraphQL\QueryHandler\QueryHandler
    properties:
      Middlewares:
        logging: '%$App\GraphQL\Middleware\LoggingMiddleware'