silverstripe-framework/docs/en/02_Developer_Guides/19_GraphQL/05_plugins/01_overview.md
2020-11-19 13:27:08 +13:00

154 lines
5.6 KiB
Markdown

---
title: What are plugins?
summary: 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](https://www.silverstripe.org/blog/community-slack-channel/),
and report any issues at [github.com/silverstripe/silverstripe-graphql](https://github.com/silverstripe/silverstripe-graphql).
Docs for the current stable version (3.x) can be found
[here](https://github.com/silverstripe/silverstripe-graphql/tree/3)
[/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).
* The `read` and `readOne` operations have:
* A `canView` plugin for hiding records that do not pass a `canView()` check
* The `read` operation has:
* A `paginateList` plugin for adding pagination arguments and types (e.g. `nodes`)
In addition to the above, the `default` schema specifically ships with an even richer set of default
plugins, including:
* A `versioning` plugin that adds `version` fields to the dataobject type (if `silverstripe/versioned` is installed)
* A `readVersion` plugin (if `silverstripe/versioned` is installed) that allows versioned operations on
`read` and `readOne` queries.
* A `filter` plugin for filtering queries (adds a `filter` argument)
* A `sort` plugin for sorting queries (adds a `sort` argument)
All of these are defined in the `modelConfig` section of the schema (see [configuring your schema](../getting_started/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**
```yaml
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**
```yaml
Page:
plugins:
inheritance: false
MyProject\MyCustomPage: {} # now has no inheritance plugin
```
Likewise, you can do the same for operations:
**app/_graphql/models.yml**
```yaml
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 schema
* `QueryPlugin`: Update a generic query
* `MutationPlugin`: Update a generic mutation
* `TypePlugin`: Update a generic type
* `FieldPlugin`: Update a field on a generic type
* `ModelQueryPlugin`: 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 model
* `ModelFieldPlugin`: 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.
```yaml
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]