Skip to content

Commit

Permalink
More updates to docs
Browse files Browse the repository at this point in the history
  • Loading branch information
GuySartorelli committed Jun 2, 2022
1 parent 0e9395c commit eb5aff9
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ SilverStripe\Core\Injector\Injector:
```


We'll now need to route the controller.

```yaml
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,31 @@ To mitigate this problem, the schema that gets executed at runtime is **generate
This code generation happens during a build step, and it is critical to run this build step
whenever the schema changes.

### Running the build
### What triggers a GraphQL code build?

The task that generates the schema code is `dev/graphql/build`.
- Any time you run the `dev/graphql/build` command to explicitly build your GraphQL schemas.
- Any time you run the `dev/build` command on your project.
- `silverstripe/graphql` will attempt to generate your schema "on-demand" on the first GraphQL request _only_ if it wasn’t already generated.

[warning]
Relying on the "on-demand" schema generation on the first GraphQL request requires some additional consideration.
See [deploying the schema](deploying_the_schema#on-demand).
[/warning]

#### Running `dev/graphql/build`

The main task for generating the schema code is `dev/graphql/build`.

`vendor/bin/sake dev/graphql/build`

This task takes an optional `schema` parameter. If you only want to generate a specific schema
(e.g. generate your custom schema, but not the CMS schema), you should pass in the name of the
schema you want to build.

[info]
If you do not provide a `schema` parameter, the task will build all schemas.
[/info]

`vendor/bin/sake dev/graphql/build schema=default`

[info]
Expand All @@ -48,13 +63,9 @@ Keep in mind that many of your changes will be in YAML, which also requires a fl

`vendor/bin/sake dev/graphql/build schema=default flush=1`

[info]
If you do not provide a `schema` parameter, the task will build all schemas.
[/info]

### Building on dev/build
#### Building on dev/build

By default, all schemas will be built as a side-effect of `dev/build`. To disable this, change
By default, all schemas will be built during `dev/build`. To disable this, change
the config:

```yaml
Expand All @@ -70,11 +81,11 @@ for initial builds and deployments, but during incremental development this can
slow things down.
To mitigate this, the generated code for each type is cached against a signature.
If the type hasn't changed, it doesn't re-render. This reduces build times to **under one second** for incremental changes.
If the type hasn't changed, it doesn't get re-built. This reduces build times to **under one second** for incremental changes.
#### Clearing the cache
#### Clearing the schema cache
Normally, we'd use `flush=1` to clear the cache, but since you almost always need to run `flush=1` with the build task, it isn't a good fit. Instead, use `clear=1`.
If you want to completely re-generate your schema from scratch, you can add `clear=1` to the `dev/graphql/build` command.

`vendor/bin/sake dev/graphql/build schema=default clear=1`

Expand All @@ -87,27 +98,26 @@ Keep in mind that it's not always explicit schema configuration changes that req
Anything influencing the output of the schema will require a build. This could include
tangential changes such as:

* Updating the `$db` array (or relationships) of a DataObject that has `fields: '*'`.
* Updating the `$db` array (or relationships) of a `DataObject` that has `fields: '*'`.
* Adding a new resolver for a type that uses [resolver discovery](../working_with_generic_types/resolver_discovery)
* Adding an extension to a DataObject
* Adding a new subclass to a DataObject that is already exposed
* If you are using Silverstripe CMS **without the [silverstripe/assets](https://github.com/silverstripe/silverstripe-assets) module installed, the build task will leave a `.graphql` file artefact in your public directory for CMS reference.
Though it doesn't contain any highly sensitive data, we recommend you block this file from being viewed by outside
traffic.


* Adding an extension to a `DataObject`
* Adding a new subclass to a `DataObject` that is already exposed

### Viewing the generated code

By default, the generated code is placed in the `.graphql/` directory in the root of your project.
It is not meant to be accessible through your webserver (which is ensured by dot-prefixing)
and keeping it outside of the `public/` webroot.
By default, the generated code is placed in the `.graphql-generated/` directory in the root of your project.
It is not meant to be accessible through your webserver, Which is ensured by d keeping it outside of the
`public/` webroot and the inclusion of a `.htaccess` file in each schema folder.

Additional files are generated for CMS operation in `public/_graphql/`, and
those are meant to be accessible through your webserver.
those _are_ meant to be accessible through your webserver.
See [Tips and Tricks: Schema Introspection](tips_and_tricks#schema-introspection)
to find out how to generate these files for your own schema.

[warning]
While it is safe for you to view these files, you should not manually alter them. If you need to make a change
to your GraphQL schema, you should [update the schema definition](configuring_your_schema) and rebuild your schema.
[/warning]

### Further reading

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
---
title: Upgrade to GraphQL v4
summary: Upgrade your Silverstripe CMS project to use graphQL version 4
title: Deploying the schema
summary: Deploy your GraphQL schema to a test or production environment
---

# Upgrading to GraphQL v4
# Getting started

[CHILDREN asList]

[alert]
You are viewing docs for a pre-release version of silverstripe/graphql (4.x).
Expand All @@ -13,94 +15,59 @@ Docs for the current stable version (3.x) can be found
[here](https://github.com/silverstripe/silverstripe-graphql/tree/3)
[/alert]

Silverstripe CMS Recipe 4.11 defaults to installing silverstripe/graphql v4. Previous releases installed version 3.

## What does silverstripe/graphql do and why are you changing this?

GraphQL is a query language for APIs. It was initially designed by Facebook but it is now used widely across the internet by all sorts of organisations including GitHub, AirBnB, Lyft, PayPal, Shopify and Silverstripe CMS … to name just a few.

`silverstripe/graphql` is an implementation of GraphQL specific to Silverstripe CMS. It is used to power some aspects of the CMS UI. It can also be used by developers to create APIs that other web services can use to read or update data in your CMS sites. This opens a lot of use cases like using Silverstripe CMS as “headless” CMS.

Until the 4.10 release, Silverstripe CMS would default to using silverstripe/graphql v3. While silverstripe/graphql v3 was sufficient to support the basic CMS use cases it was being used for, it was not performant enough to build more complex applications.

`silverstripe/graphql` v4 is a complete rewrite and provides substantial performance improvements.

`silverstripe/graphql` v4 provides developers a first class tool for building APIs and allowing third party services to integrate with their Silverstripe CMS websites.

## That sounds risky, do I absolutely have to use version 4?

Silverstripe CMS has been shipping with dual support for `silverstripe/graphql` v3 and v4 since the 4.8 release. Until now `silverstripe/graphql` v4 had been in alpha and you had to explicitly opt-in to get it. At Silverstripe, we are already using `silverstripe/graphql` v4 in production on several projects.

All the supported Silverstripe CMS modules that use `silverstripe/graphql` have dual-support for version 3 and version 4. If you wish to stay on `silverstripe/graphql` v3, you can do so and it will not block you from upgrading to Silverstripe CMS 4.11.
## Deploying the schema

We will maintain support for `silverstripe/graphql` v3 in Silverstripe CMS 4 for the foreseeable future. Any change to this policy will be announced at least 6 months in advance.
One way or another, you must get the `.graphql-generated` and `public/_graphql` folders into your test and production environments for Silverstripe CMS (and your own custom queries) to work as expected. There are many ways to do so. The options below are listed in order of complexity.

### Opting out of `silverstripe/graphql` v4 and sticking to version 3
### Options for any hosting solution

If your project composer.json file already explicitly requires silverstripe/graphql, you don’t need to do anything.
#### Commit the schema to version control {#commit-to-vcs}

If your project uses silverstripe/recipe-cms, composer will try to install `silverstripe/graphq` v4.0 when you upgrade to the 4.11 release. To stay on silverstripe/graphql:^3, you’ll need to explicitly require `silverstripe/graphql` v3.8.
A simplistic approach is to build the schema in your local development environment and add the `.graphql-generated` and `public/_graphql` folders to your version control system. With this approach you would most likely want to disable schema generation at `dev/build`.

```
composer require silverstripe/graphql:^3
```
This approach has the advantage of being very simple, but it will pollute your commits with massive diffs for the generated code.

To validate which version of `silverstripe/graphql` your project is using, run this composer command:
`composer show silverstripe/graphql`
#### Explicitly build the schema during each deployment {#build-during-deployment}

To view which dependencies require `silverstripe/graphql`, run this composer command:
`composer why silverstripe/graphql`
Many projects will automatically run a `dev/build` whenever they deploy a site to their production environment. If that’s your case, then you can just let this process run normally and generate the `.graphql-generated` and `public/_graphql` folders for you. This will allow you to add these folders to your `.gitignore` file and avoid tracking the folder in your version control system.

## How do I get this thing working?
Be aware that for this approach to work, the process executing the `dev/build` must have write access to create the folders (or you must create those folders yourself, and give write access to those folders specifically), and for multi-server environments a `dev/build` or `dev/graphql/build` must be executed on each server hosting your site after each deployment.

Part of the reason why `silverstripe/graphql` v4 is so much faster than v3 is that it has a “code generation” step. Silverstripe CMS will generate PHP classes for your GraphQL schemas and stores them in a `.graphql-generated` folder in the root of your project.
#### Use a CI/CD pipeline to build your schema {#using-ci-cd}

### What triggers a GraphQL code build?

- This folder will automatically be generated when you run a `dev/build` on your project.
- You can also run the `dev/graphql/build` command to explicitly build your GraphQL schemas.
- Silverstripe CMS will attempt to generate your schema on the first graphql request if it wasn’t already generated.

### Deploying your `.graphql-generated` folder

One way or another, you must get this `.graphql-generated` folder into your production environment for Silverstripe CMS to work as expected. There are many ways to do so.

#### Commit `.graphql-generated`

A simplistic approach is to build the `.graphql-generated` in your local development environment and add it to your source control system.

This approach has the advantage of being very simple, however it will pollute your commits with massive diff for the generated code.
Projects with more sophisticated requirements or bigger schemas exposing more than 100 `DataObject` classes may want to consider using a continuous-integration/continuous-deployment (CI/CD) pipeline to build their GraphQL schema.

#### Run a dev/build on each deployment
Many projects will automatically run a dev/build whenever they deploy a site to their production environment. If that’s your case, then you can just let this process run normally and generate the `.graphql-generated` folder for you. This will allow you to add `.graphql-generated` to your `.gitignore` file and avoid tracking the folder in your source control system.
In this kind of setup, you would need to update your deployment script to run the `dev/graphql/build` command to build the `.graphql-generated` and `public/_graphql` folders.

Be aware that for this approach to work, the process executing the `dev/build` must have write access to create the `.graphql-generated` folder and a `dev/build` or `dev/graphql/build` must be executed on each server hosting your site after each deployment.
### Multi-server hosting solutions {#multi-server}

For example, if your site is hosted in an environment with multiple servers and you only run a dev/build on one single server, then the other servers won’t have a `.graphql-generated` folder. This might also impact you if your project is hosted in an environment configured to auto-scale with demand.
If your site is hosted in an environment with multiple servers or your project is hosted in an environment configured to auto-scale with demand, there are some additional considerations. For example if you only generate the schema on one single server, then the other servers won’t have a `.graphql-generated` or `public/_graphql` folder (or those folders will be empty if you manually created them).

Alternatively, you could configure a process to sync your `.graphql-generated` folder across all your servers. In that case you only need to run `dev/build` or `dev/graphql/build` on the server with the original folder.
#### Rely on "on-demand" schema generation on the first GraphQL request {#on-demand}

#### Rely on “on-demand” schema generation on the first GraphQL request
When the first GraphQL schema request occurs, Silverstripe CMS will attempt to build the `.graphql-generated` folder “on-demand” if it’s not already present on the server. This will impose a one-time hit on the first graphQL request. If your project defines multiple schemas, only the schema that is being accessed will be generated.
When the first GraphQL schema request occurs, Silverstripe CMS will attempt to build the `.graphql-generated` and `public/_graphql` folders "on-demand" if they're not already present on the server. Similarly, if the folders are present but empty, it will build the schema "on-demand". This will impose a one-time performance hit on the first GraphQL request. If your project defines multiple schemas, only the schema that is being accessed will be generated.

For most common use cases, this process is relatively fast. For example, the GraphQL schema that is used to power the CMS can be built in about a quarter of a second.

While benchmarking schema generation performance, we measured that a schema exposing 180 DataObjects with 1600 relations could be built on-demand in less than 6 seconds on a small AWS instance.

Our expectation is that on-demand schema generation will be appropriate for most projects with small or medium schemas.
Our expectation is that on-demand schema generation will be performant for most projects with small or medium schemas.

#### Use a CI/CD pipeline to build your schema
[warning]
Note that with this approach you will need to remove or empty the `.graphql-generated` and `public/_graphql` folders on each server for each deployment that includes a change to the schema definition, or you risk having an outdated GraphQL schema. The "on-demand" schema generation does not detect changes to the schema definition.
[/warning]

Projects with more sophisticated requirements or bigger schemas exposing more than 100 `DataObject` classes may want to consider using a continuous-integration/continuous-deployment (CI/CD) pipeline to build their GraphQL schema.
#### Build the schema during/before deployment and share it across your servers {#multi-server-shared-dirs}

If you have a particularly large schema, you may want to ensure it is always built before the first GraphQL request. It might make sense for you to sync your `.graphql-generated` and `public/_graphql` folders across all your servers using an EFS or similar mechanism. In that case you only need to run `dev/build` or `dev/graphql/build` on the server with the original folder - but bear in mind that this may have a performance impact.

In this kind of setup, you would need to update your deployment script to run the `dev/graphql/build` command to build the `.graphql-generated` folder.
### Performance considerations when building the GraphQL schema {#performance-considerations}

## Performance considerations when building graphQL schema
The main driver in the resources it takes to build a GraphQL schema is the number DataObjects and the number of exposed relations in that schema. In most cases, not all DataObject in your database will be included in your schema. DataObjects not included in your schema will not impact the time or memory needed to build it.
The main driver in the resources it takes to build a GraphQL schema is the number DataObjects and the number of exposed relations in that schema. In most cases, not all DataObject in your database will be included in your schema - best practice is to only add classes you will need to query to your schema definition. DataObjects not included in your schema will not impact the time or memory needed to build it.

Silverstripe CMS defines an admin schema it uses for its own purpose. This schema is relatively small and has a negligible performance impact.
Silverstripe CMS defines an "admin" schema it uses for its own purpose. This schema is relatively small and has a negligible performance impact.

As an indication, we ran some benchmarks on a t3.micro AWS instance. Those numbers may not be representative of the performance in your own environment. If you intend to build large graphQL schemas, you should take the time to run your own benchmarks and adjust your deployment strategy accordingly.
As an indication, we ran some benchmarks on a t3.micro AWS instance. Those numbers may not be representative of the performance in your own environment. If you intend to build large GraphQL schemas, you should take the time to run your own benchmarks and adjust your deployment strategy accordingly.

DataObjects in schema | Build time (ms) | Memory use (MB)
-- | -- | --
Expand All @@ -111,15 +78,14 @@ DataObjects in schema | Build time (ms) | Memory use (MB)
250 | 5070 | 114
500 | 11,540 | 208

## Gotchas
### Gotchas

### Permissions of the `.graphql-generated` folder
The process that is generating the `.graphql-generated` folder must have write permissions to create the folder and to update existing files. If different users are used to generate the `.graphql-generated` folder, then you must make sure that each user retains write access on the folder.
#### Permissions of the `.graphql-generated` and `public/_graphql` folders {#gotchas-permissions}

For example, if you manually run a `dev/build` under a foobar user, `.graphql-generated` folder will be owned by foobar. If your web server is running under the www-data user and you try to call `dev/graphql/build` in your browser, you might get an error if www-data doesn’t have write access.
The process that is generating these folders must have write permissions to create the folder and to update existing files. If different users are used to generate the folders, then you must make sure that each user retains write access on them.

### Tracking or ignoring the `.graphql-generated` folder
For example, if you manually run a `dev/build` under a foobar user, the folders will be owned by foobar. If your web server is running under the www-data user and you try to call `dev/graphql/build` in your browser, you might get an error if www-data doesn’t have write access.

Existing projects will not have an entry in their `.gitignore` file for `.graphql-generated`. If you do not want to track the `.graphql-generated` folder, you’ll have to manually add this entry to your `.gitignore`.
### Further reading

The `.gitignore` file in `silverstripe/installer` 4.11 has been updated to ignore the `.graphql-generated` folder. If you start a new project from `silverstripe/installer` 4.11.0 and want to track the `.graphql-generated` folder, you’ll have to update your `.gitignore` file.
[CHILDREN]
Loading

0 comments on commit eb5aff9

Please sign in to comment.