DOCS: Bulk loader graphql docs (#10203)

* DOCS: Bulk loader graphql docs

* Add code example, add module syntax
This commit is contained in:
Aaron Carlino 2022-01-21 10:22:54 +13:00 committed by GitHub
parent fc707cc10d
commit 5bb203e16a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 144 additions and 5 deletions

View File

@ -118,6 +118,8 @@ types:
# your generic types here # your generic types here
models: models:
# your dataobjects here # your dataobjects here
bulkLoad:
# your bulk loader directives here
queries: queries:
# your queries here # your queries here
mutations: mutations:
@ -154,6 +156,11 @@ be implicitly placed in the corresponding section of the schema.
# my type definitions here # my type definitions here
``` ```
**app/_graphql/bulkLoad/bulkLoad.yml**
```yaml
# my bulk loader directives here
```
##### Namespacing by filename ##### Namespacing by filename
If the filename is named one of the four keywords above, it will be implicitly placed If the filename is named one of the four keywords above, it will be implicitly placed
@ -168,6 +175,12 @@ in the corresponding section of the schema. **This only works in the root source
```yaml ```yaml
# my models here # my models here
``` ```
**app/_graphql/bulkLoad.yml**
```yaml
# my bulk loader directives here
```
#### Going even more granular #### Going even more granular
These special directories can contain multiple files that will all merge together, so you can even These special directories can contain multiple files that will all merge together, so you can even

View File

@ -1,5 +1,5 @@
--- ---
title: The DataObject model type title: Adding DataObjects to the schema
summary: An overview of how the DataObject model can influence the creation of types, queries, and mutations summary: An overview of how the DataObject model can influence the creation of types, queries, and mutations
--- ---
@ -199,6 +199,132 @@ convention in GraphQL APIs to use lowerCamelCase fields, so this is given by def
[/notice] [/notice]
### Bulk loading models
It's likely that in your application, you have a whole collection of classes you want exposed to the API, with roughly
the same fields and operations exposed on them. It can be really tedious to write a new declaration for every single
dataobject in your project, and as you add new ones, there's a bit of overhead in remembering to add it to the
GraphQL schema.
Common use cases might be:
* Add everything in `App\Models`
* Add every implementation of `BaseElement`
* Add anything with the `Versioned` extension
* Add everything that matches `src/*Model.php`
You can create logic like this using the `bulkLoad` configuration file, which allows you to specify groups of directives
that load a bundle of classes and apply the same set of configuration to all of them.
**_graphql/bulkLoad.yml**
```yaml
elemental: # An arbitrary key to define what these directives are doing
# Load all content blocks
load:
inheritanceLoader:
include:
- DNADesign\Elemental\Models\BaseElement
exclude:
- MyApp\Elements\MySecretElement
# Add all fields and read operations
apply:
fields:
'*': true
operations:
read: true
readOne: true
app:
# Load everything in our app that has the Versioned extension
load:
namespaceLoader:
include:
- MyApp\Models\*
extensionLoader:
include:
- SilverStripe\Versioned\Versioned
filepathLoader:
exclude:
- app/src/Models/*.secret.php
apply:
fields:
'*': true
operations:
'*': true
```
By default, four loaders are provided to you to help gather specific classnames:
#### By namespace
* **Identifier**: `namespaceLoader`
* **Description**: Include or exclude classes based on their namespace
* **Example**: `include: [MyApp\Models\*]`
#### By inheritance
* **Identifier**: `inheritanceLoader`
* **Description**: Include or exclude everything that matches or extends a given base class
* **Example**: `include: [DNADesign\Elemental\Models\BaseElement]`
#### By applied extension
* **Identifier**: `extensionLoader`
* **Description**: Include or exclude any class that has a given extension applied
* **Example**: `include: [SilverStripe\Versioned\Versioned]`
#### By filepath
* **Identifier**: `filepathLoader`
* **Description**: Include or exclude any classes in files matching a given glob expression, relative to the base path. Module syntax is allowed.
* **Examples**:
- `include: [ 'src/models/*.model.php' ]`
- `include: [ 'somevendor/somemodule: src/Models/*.php' ]`
Each block starts with a collection of all classes that gets filtered as each loader runs. The primary job
of a loader is to _remove_ classes from the entire collection, not add them in.
[info]
`exclude` directives will always supersede `include` directives.
[/info]
[info]
If you find that this paints with too big a brush, you can always override individual models explicitly in `models.yml`.
The bulk loaders run _before_ the models.yml config is loaded.
[/info]
#### DataObjects subclasses are the default starting point
Because this is Silverstripe CMS, and it's likely that you're using dataobject models only, the bulk loaders start with an
initial filter, which is defined as follows:
```yaml
inheritanceLoader:
include:
- SilverStripe\ORM\DataObject
```
This ensures that at a bare minimum, you're always filtering by dataobject classes only. If, for some reason, you
have a non-dataobject class in `App\Models\*`, it will automatically be filtered out due to this default setting.
This default is configured in the `defaultBulkLoad` setting in your schema config. Should you ever want to disable
that, just set it to `false`.
**_graphql/config.yml**
```
defaultBulkLoad: false
```
#### Creating your own bulk loader
Bulk loaders must extend `SilverStripe\GraphQL\Schema\BulkLoader\AbstractBulkLoader`. They need to declare an
identifier (e.g. `namespaceLoader`) to be referenced in the config, and they must provide a
`collect(Collection $collection): Collection` which returns a new `Collection` instance once the loader has done its
work parsing through the `include` and `exclude` directives.
Bulk loaders are automatically registered. Just creating the class is all you need to do to have it available for use
in your `bulkLoad.yml` file.
### Customising model fields ### Customising model fields
You don't have to rely on the model to tell you how fields should resolve. Just like You don't have to rely on the model to tell you how fields should resolve. Just like
@ -241,9 +367,9 @@ Page:
paginateList: false # don't paginate the read operation paginateList: false # don't paginate the read operation
``` ```
### Blacklisted fields {#blacklisted-fields} ### Disallowed fields {#disallowed-fields}
While selecting all fields via `*` is usedful, there are some fields that you While selecting all fields via `*` is useful, there are some fields that you
don't want to accidentally expose, especially if you're a module author don't want to accidentally expose, especially if you're a module author
and expect models within this code to be used through custom GraphQL endpoints. and expect models within this code to be used through custom GraphQL endpoints.
For example, a module might add a secret "preview token" to each `SiteTree`. For example, a module might add a secret "preview token" to each `SiteTree`.
@ -251,8 +377,8 @@ A custom GraphQL endpoint might have used `fields: '*'` on `SiteTree` to list pa
on the public site, which now includes a sensitive field. on the public site, which now includes a sensitive field.
The `graphql_blacklisted_fields` property on `DataObject` allows you to The `graphql_blacklisted_fields` property on `DataObject` allows you to
blacklist fields globally for all GraphQL schemas. disallow fields globally for all GraphQL schemas.
This blacklist applies for all operations (read, update, etc). This block list applies for all operations (read, update, etc).
**app/_config/graphql.yml** **app/_config/graphql.yml**
```yaml ```yaml