--- 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 interfaces, unions, 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]