5.6 KiB
title | summary |
---|---|
What are plugins? | An overview of how plugins work with the GraphQL schema |
Plugins
[CHILDREN asList]
[alert] You are viewing docs for a pre-release version of silverstripe/graphql (4.x). Help us improve it by joining #graphql on the Community Slack, and report any issues at github.com/silverstripe/silverstripe-graphql. Docs for the current stable version (3.x) can be found here [/alert]
What are plugins?
Plugins are used to distribute reusable functionality across your schema. Some examples of commonly used plugins include:
- Adding versioning arguments to versioned DataObjects
- Adding a custom filter/sort arguments to DataObject queries
- Adding a one-off
VerisionedStage
enum to the schema - Ensuring
Member
is in the schema - And many more...
Default plugins
By default, all schemas ship with some plugins installed that will benefit most use cases:
- The
DataObject
model (i.e. any dataobject based type) has:- An
inheritance
plugin that builds the__extends
field, and merges ancestral fields. - An
inheritedPlugins
plugin (a bit meta!) that merges plugins from ancestral types into descendants. installed).
- An
- The
read
andreadOne
operations have:- A
canView
plugin for hiding records that do not pass acanView()
check
- A
- The
read
operation has:- A
paginateList
plugin for adding pagination arguments and types (e.g.nodes
)
- A
In addition to the above, the default
schema specifically ships with an even richer set of default
plugins, including:
- A
versioning
plugin that addsversion
fields to the dataobject type (ifsilverstripe/versioned
is installed) - A
readVersion
plugin (ifsilverstripe/versioned
is installed) that allows versioned operations onread
andreadOne
queries. - A
filter
plugin for filtering queries (adds afilter
argument) - A
sort
plugin for sorting queries (adds asort
argument)
All of these are defined in the modelConfig
section of the schema (see configuring your schema). For reference, see the graphql configuration in silverstripe/admin
, which applies
these default plugins to the default
schema.
Overriding default plugins
You can override default plugins generically in the modelConfig
section.
app/_graphql/modelConfig.yml
DataObject:
plugins:
inheritance: false # No dataobject models get this plugin unless opted into
operations:
read:
plugins:
paginateList: false # No dataobject models have paginated read operations unless opted into
You can override default plugins on your specific dataobject type and these changes will be inherited by descendants.
app/_graphql/models.yml
Page:
plugins:
inheritance: false
MyProject\MyCustomPage: {} # now has no inheritance plugin
Likewise, you can do the same for operations:
app/_graphql/models.yml
Page:
operations:
read:
plugins:
readVersion: false
MyProject\MyCustomPage:
operations:
read: true # has no readVersion plugin
What plugins must do
There isn't a huge API surface to a plugin. They just have to:
- Implement at least one of several plugin interfaces
- Declare an identifier
- Apply themselves to the schema with the
apply(Schema $schema)
method - Be registered with the
PluginRegistry
Available plugin interfaces
Plugin interfaces are all found in the namespace SilverStripe\GraphQL\Schema\Interfaces
SchemaUpdater
: Make a one-off, context-free update to the schemaQueryPlugin
: Update a generic queryMutationPlugin
: Update a generic mutationTypePlugin
: Update a generic typeFieldPlugin
: Update a field on a generic typeModelQueryPlugin
: Update queries generated by a model, e.g.readPages
ModelMutationPlugin
: Update mutations generated by a model, e.g.createPage
ModelTypePlugin
: Update types that are generated by a modelModelFieldPlugin
: Update a field on types generated by a model
Wow, that's a lot of interfaces, right? This is owing mostly to issues around strict typing between interfaces, and allows for a more expressive developer experience. Almost all of these interfaces have the same requirements, just for different types. It's pretty easy to navigate if you know what you want to accomplish.
Registering plugins
Plugins have to be registered with Injector.
SilverStripe\Core\Injector\Injector:
SilverStripe\GraphQL\Schema\Registry\PluginRegistry:
constructor:
- 'MyProject\Plugins\MyPlugin'
[info]
The key myPlugin
is arbitrary. The identifier of the plugin is obtained procedurally.
[/info]
Resolver middleware and afterware
The real power of plugins is the ability to distribute not just configuration across the schema, but more importantly, functionality.
Fields have their own resolvers already, so we can't really get into those to change their functionality without a massive hack. This is where the idea of resolver middleware and resolver afterware comes in really useful.
Resolver middleware runs before the field's assigned resolver Resolver afterware runs after the field's assigned resolver
Middlewares and afterwares are pretty straightforward. They get the same $args
, $context
, and $info
parameters as the assigned resolver, but the first argument, $result
is mutated with each resolver.
Further reading
[CHILDREN]