diff --git a/docs/_config.yml b/docs/_config.yml index d20ac69..1df6436 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -23,8 +23,8 @@ sidebar_categories: Platform: - platform/schema-registry - - platform/client-awareness - platform/schema-validation + - platform/client-awareness - platform/operation-registry - platform/editor-plugins - platform/tracing diff --git a/docs/source/images/schema-checks.png b/docs/source/images/schema-checks.png new file mode 100644 index 0000000..b397296 Binary files /dev/null and b/docs/source/images/schema-checks.png differ diff --git a/docs/source/images/schema-history.png b/docs/source/images/schema-history.png new file mode 100644 index 0000000..e45a692 Binary files /dev/null and b/docs/source/images/schema-history.png differ diff --git a/docs/source/img/schema-validation/service-checks.png b/docs/source/img/schema-validation/service-checks.png new file mode 100644 index 0000000..56c37b2 Binary files /dev/null and b/docs/source/img/schema-validation/service-checks.png differ diff --git a/docs/source/platform/schema-registry.md b/docs/source/platform/schema-registry.md index c0d4e59..caba4b8 100644 --- a/docs/source/platform/schema-registry.md +++ b/docs/source/platform/schema-registry.md @@ -1,102 +1,92 @@ --- -title: Registering your schema -description: How to publish your schema to the Apollo registry +title: Tracking schema change history +description: Connect to the Apollo schema registry and track changes in your schema over time --- -A schema is the center point of all GraphQL applications. It powers incredible development tools, is an always up to date set of documentation, and creates an enforcable contract between clients and servers through validation. Since this is such a center point of how teams work on GraphQL, the Apollo GraphQL Platform provides a free schema registry for teams of all sizes to use. In storing a schema in the registry, teams can share an always up to date picture of their data model into every facet of their workflow. +As GraphQL scales in an organization, teams often find that growing and evolving their schema over time becomes difficult to manage. Product teams want to move fast with GraphQL, but they also want reassurance that their code changes won't break existing clients. At scale, you might have hundreds of clients querying against a single schema. How can we ensure that adding or removing a field, type, or argument won't break existing clients and cause a service outage? -

Benefits of publishing a schema

+The [Apollo platform](/docs/intro/platform.html) includes a free schema registration service to help teams of all sizes easily evolve their API over time. Just like it's important to track source code in a version control system, it's a [best practice](https://principledgraphql.com/integrity#3-track-the-schema-in-a-registry) to track the definition of your graph in a schema registry. Once a team registers its schema with Apollo, developers have visibility into when a change was made, who made the change, and the type of change. The registry also supports tracking multiple variants of the graph (for example, staging vs. production). -The Apollo schema registry provides a number of benefits to help teams collaborate and ship high quality software faster. A few of these benefits are: +

Using the Schema Registry

-* Powering editor tools like the [Apollo VS Code extension](https://marketplace.visualstudio.com/items?itemName=apollographql.vscode-apollo) -* Empowering better code reviews and safer changes with [schema validation](./schema-validation.html) -* Having a single point of knowledge for all teams to view through the [Apollo schema explorer](https://engine.apollographql.com) -* Sharing upcoming changes with [schema tags](#schema-tags) -* Protecting the server along with the [Apollo operation registry](./operation-registry.html) -* Having a historical view of how a schema changes with the [Apollo schema history tab in Engine](#history) +To get started using Apollo's schema registration service, you'll need to configure your repository to be an Apollo project by: -

Publishing a schema

+1. [Installing the Apollo CLI](#install-cli) +1. [Creating a `.env` file in the root of your project with an `ENGINE_API_KEY`](#api-key) +1. [Creating an `apollo.config.js` file at the root of your project and adding the right configuration](#apollo-config) -Publishing schemas to the Apollo schema registry is done by pushing a GraphQL service to Engine. A service represents information about the schema and how it can be run. Part of this push includes registering the service's schema in the schema registry. +#### CLI commands -To begin using the schema registry, the first step that needs to be done is pushing a service into the registry. This is done by using the [`apollo` command line interface (CLI)](https://npm.im/apollo). +Once you have the Apollo CLI installed, your Engine API key set up, and your Apollo config created, you will be ready to start connecting to the schema registry. The main commands to interface with the registry are: -

Install Apollo CLI

+- `apollo service:push`: push a new schema to the registry +- `apollo service:check`: compare the local schema against collected usage metrics and validate if proposed changes will break any live queries -To install the [`apollo`](https://npm.im/apollo) CLI, ensure that `node` and `npm` are installed, then run: +Type `apollo service --help` for full details on the commands available in the CLI. + +

Install the Apollo CLI

+ +To install the [`apollo` CLI](https://npm.im/apollo), ensure that `node` and `npm` are both installed, then run: ```bash npm install --global apollo ``` -> Note: This guide will utilize the global installation method, but the `apollo` command can also be installed in a project's `devDependencies` and used via [`npm-scripts`](https://docs.npmjs.com/misc/scripts) or [`npx`](https://npm.im/npx). +> **Note:** This guide will utilize the global installation method, but the `apollo` command can also be installed in a project's `devDependencies` and used via [`npm-scripts`](https://docs.npmjs.com/misc/scripts) or [`npx`](https://npm.im/npx). -

Pushing a service

+

Get your Engine API key

-Once the `apollo` command is installed, the `apollo service:push` command is used to publish a schema to Apollo Engine. +To get an API key, you will need to [log in to Engine](https://engine.apollographql.com) and create a new service by clicking the "Add Service" button. If you already have a service, get your API key by visiting your service's settings page. Once you have your API key, add it to your `.env` file like so: -To push a service, start the GraphQL server and run the following command, substituting the appropriate GraphQL endpoint URL and an API key: - -> An API key can be obtained from a service's _Settings_ menu within the [Engine dashboard](https://engine.apollographql.com/). - -```bash -apollo service:push --key="" --endpoint="https://example.com/graphql" +``` +ENGINE_API_KEY=service:foobar:d1rzyrmanmrZXxTTQLxghX ``` -> For accuracy, it's best to retrieve the schema from a running GraphQL server (with introspection enabled), though local files representing a schema can also be used. See the [configuration options](../references/apollo-config.html) for more information. +The Apollo CLI uses your Engine API key to authenticate with the registry when it pushes your schema. -

Viewing a published schema

+> **Note:** Make sure your `.env` file is in the root of your project so the Apollo CLI knows where to find it. You can also export `ENGINE_API_KEY` as an environment variable. -Now that the service has been pushed, it can be viewed by going to [Engine](https://engine.apollographql.com) and browsing to the service's dashboard. The schema that was pushed should now appear with overal information about its number of types and fields, as well as full information about every type, argument, and description of the schema. With this done, teams can now use productivity boosters like the [Apollo VS Code extension](./editor-plugins.html) +

Create an `apollo.config.js` file

-

Schema tags

+The commands executed through the Apollo CLI will be looking for your Apollo config to inform their behavior. Visit the [Apollo config docs](/docs/references/apollo-config.html#service-config) for full details on how to set up your `apollo.config.js` file in your application. -Product cycles move incredibly fast and coordination of teams is critical to shipping features quickly. To enable this coordination, the Apollo schema registry allows teams to push proposed or future versions of their schema to the registry so teams can use them in their editors, validate against them, and have a center point of truth even for the future of their graph. - -There are two parts to getting the most out of schema tags. The first is pushing the tagged schema to the registry: - -

Publishing a tag

- -Publishing a tagged version of a schema is done using the same command as publishing the initial schema. In fact, the `apollo service:push` command publishes a schema under a tag called `current`. To publish a tagged version, run the server with the new schema and then push the service: - -```bash -apollo service:push --key="" --endpoint="https://example.com/graphql" --tag=beta -``` - -The only change in this push is the addition of the `--tag` flag on the end of the push command. - -

Running a tagged schema

- -To get the most out of using tagged schemas, teams can send metrics to [Engine](https://engine.apollographql.com) associated with this tag. This enables a single service to be tracked in production, staging, and any other environment a schema is being run. To track metrics with a schema, make sure the latest Apollo Server is installed and turn on tagging in one of two ways: - -1. Starting up the service with an environment variable called `ENGINE_SCHEMA_TAG` will link metrics sent to Engine with the value of that environment variable. This is the best way to associate metrics so that the schema tag isn't hardcoded into the server. -2. Alternatively, schema tag can be set within the `engine` settings of Apollo Server 2.2 and up: +To set up schema registration, you'll need to configure a source that the CLI can fetch your schema from like so: ```js -const server = new ApolloServer({ - // rest of normal server settings - engine: { - schemaTag: 'beta', - }, -}); +module.exports = { + service: { + endpoint: { + url: "http://localhost:4000" + } + // OR + localSchemaFile: './path/to/schema.graphql' + } +}; ``` -Both the new version of the schema, as well as its performance and error metrics can be viewed using [Engine](https://engine.apollographql.com) and can even be used with [schema validation](./schema-validation.html). +

Registering a schema

-

Schema history

+You push a schema to the registry by running `apollo service:push` from within your repository. The CLI will know where to fetch your local schema from based on the configuration you gave in your `apollo.config.js` file. Each time a new version of your schema is pushed, it is logged in your schema history and it becomes the basis of comparison for `apollo service:check`. -As your schema grows and evolves to meet the needs of your product, it is helpful to see a history of changes for a team. This allows everyone to know when new features were introduced, when old fields were removed, and even link back to the commit that caused the change. Apollo Engine provides all the tooling needed to track this history in a simple way. Every time your schema is updated, you can simply run the [`apollo service:push`](#publish) command to keep an up to date history of your schema. +Here's what running `apollo service:push` will look like: -Each time a schema is published, it becomes the basis for comparison for validating future schemas and avoiding breaking changes. Therefore, a service should be pushed to [Engine](https://engine.apollographql.com) each time a new schema is deployed. +``` +~/Development/apollo/example$ apollo service:push + ✔ Loading Apollo Project + ✔ Uploading service to Engine -This is best accomplished from automatic steps within a continuous integration workflow and an example CircleCI configuration is available below. +id schema tag +────── ──────────── ─────── +190330 example-4218 current +``` -In order to keep provide accurate analysis of breaking changes, it important to run the `apollo service:push` command each time the schema is deployed. This can be done by configuring continuous integration to run `apollo service:push` automatically on the `master` branch (or the appropriate mainline branch). +### Hooking into CI -Below is a sample configuration for pushing a schema using CircleCI: +To get the full value out of Apollo's platform, the schema registry should be an accurate representation of what's running live on your services. To achieve this, you should add the `apollo service:push` command to your continuous delivery pipeline so that your schema is pushed to the registry on every deploy. This is how you will maintain accurate schema change tracking, schema change validation, schema documentation, etc. -```yaml +Here is a sample configuration for pushing a schema using CircleCI: + +```yaml line=13,29-31 version: 2 jobs: @@ -122,14 +112,65 @@ jobs: # commands against it - run: sleep 5 - # This will authenticate using the `ENGINE_API_KEY` environment - # variable. If the GraphQL server is available elsewhere than - # http://localhost:4000/graphql, set it with `--endpoint=`. - - # When running on the 'master' branch, publish the latest version + # When running on the 'master' branch, push the latest version # of the schema to Apollo Engine. - run: | if [ "${CIRCLE_BRANCH}" == "master" ]; then apollo service:push --tag=master fi ``` + +

Viewing schema change history

+ +Changes made to your schema over time can be tracked in Apollo's UI in Engine by browsing to the History page in your service. + +Once you have pushed your schema, you can view it through [Apollo Engine](https://engine.apollographql.com) by browsing to the History page in your Service. The pushed schema will appear in your history log along with a list of changes comparing it to the previously pushed versions of your schema. You can view the full contents of the most recently pushed version of your schema in the Explorer page. + +Schema history page in the Engine UI + +

Managing environments

+ +Product cycles move fast, and it's common for a schemas to be slightly different across environments as changes make their way through your system. To accommodate for this, the schema registry allows each schema to be registered under a "schema tag". Tags are mostly commonly used to represent environments. + +There are two parts to setting up schema tags: + +1. [Configuring each `service:push` to send along a tag with each schema push.](#registry-tag) +1. [Configuring metrics sent from your server to send along a tag with each trace.](#metrics-tag) + +

Register a schema to a tag

+ +To register your schema to a specific tag, simply add the `--tag=` flag to your push command: + +```bash +apollo service:push --tag=beta +``` + +> **Note:** Untagged pushes to the registry will be associated with the default tag, `current`. + +

Send tagged metrics

+ +Tagging both schemas pushes and metrics sent enables a single service to be tracked across production, staging, and any other environments exposing a schema. + +Configure the metrics sent to [Engine](https://engine.apollographql.com) from your server to send a tag with each trace in one of two ways: + +1. Starting up the service with an environment variable called `ENGINE_SCHEMA_TAG`. This will link metrics sent to Engine with the value of that environment variable. This is the best way to associate metrics so that the schema tag isn't hardcoded into the server. +1. Alternatively, add the `schemaTag` option to your Apollo Server configuration (only works for Apollo Server 2.2+): + +```js line=5 +const server = new ApolloServer({ + ... + engine: { + apiKey: "", + schemaTag: "beta" + } +}); +``` + +

Tools that use the schema registry

+ +An up-to-date schema in Apollo's schema registry enables a number of workflow benefits through integrations with other tools. A registered schema combined with: + +- The [Apollo VS Code extension](https://marketplace.visualstudio.com/items?itemName=apollographql.vscode-apollo) provides built-in linting on queries by validating against the schema in your registry, and annotates fields on your queries with performance indicators collected in Apollo's trace warehouse. +- [Schema validation](./schema-validation.html) creates a diff between your local schema and the last schema pushed to the registry, and validates this diff against live traffic seen on your endpoint to make sure you never accidentally deploy a breaking schema change to production. +- The [Schema History](#history) keeps track of all the changes made to your schema over time. +- The [Schema Explorer](https://engine.apollographql.com) links the fields in your schema to clients and queries that are using them. diff --git a/docs/source/platform/schema-validation.md b/docs/source/platform/schema-validation.md index 2e5bfc8..3fe2c58 100644 --- a/docs/source/platform/schema-validation.md +++ b/docs/source/platform/schema-validation.md @@ -1,152 +1,179 @@ --- title: Validating schema changes -description: How to validate your schema in your existing CI workflow +description: Check if proposed schema changes are safe or breaking by comparing against live server traffic --- -The Apollo GraphQL Platform allows developers to confidently iterate a GraphQL schema by validating the new schema against field-level usage data from the previous schema. By knowing exactly which clients will be broken by a new schema, developers can avoid inadvertently deploying a breaking change. +As GraphQL scales within an organization, it becomes harder to evolve the schema while guaranteeing that no query or client will ever break from a change. Some organizations take the approach of just _never_ making schema changes that might be breaking; however, managing an only-ever-growing schema is unnecessarily difficult for most teams. It can actually be very safe to evolve the schema through field removals and return type changes if you have the right tools to guarantee that no such change will ever break an active query. -A GraphQL schema can change in a number of ways between releases and, depending on the type of change, can affect clients in a variety of ways. Since changes can range from "decidedly safe" to "certain breakage", it's helpful to use schema tools which are aware of actual API usage. +As such, schema change validation is one of the cornerstones of the [Apollo Platform](/docs/intro/platform.html) and we've built a set of tools to make the workflow possible. -By comparing a new schema to the last published schema, the Apollo Platform can highlight points of concern by showing detailed schema changes alongside current usage information for those fields. With this pairing of data, the risks of changes can be greatly reduced. +> **Note:** Schema validation is an Apollo Platform feature available on the [_Team_ and _Enterprise_ plans](https://www.apollographql.com/plans/). To get started with the Apollo Platform, begin with [the documentation](https://www.apollographql.com/docs/). If you already have an Engine account, upgrade to a Team plan [here](https://engine.apollographql.com/trypro). -

Understanding schema changes

+

How it works

-Versioning is a technique to prevent necessary changes from becoming "breaking changes" which affect the existing consumers of an API. These iterations might be as trivial as renaming a field, or as substantial as refactoring the whole data model. +The schema validation mechanism utilizes both Apollo's schema registry and Apollo's trace warehouse. The **schema registry** is used to identify a "schema diff" with changes between schema versions. The **trace warehouse** is used to identify which clients and which operations are using which fields in the schema in real time. We compare each change in the schema diff against the live usage data to determine if that change will be a "breaking change" for any clients. -Developers who have worked with REST APIs in the past have probably recognized various patterns for versioning the API, commonly by using a different URI (e.g. `/api/v1`, `/api/v2`, etc.) or a query parameter (e.g. `?version=1`). With this technique, an application can easily end up with many different API endpoints over time, and the question of _when_ an API can be deprecated can become problematic. +Here's how it works: -It might be tempting to version a GraphQL API the same way, but it's unnecessary with the right techniques. By following the strategies and precautions outlined in this guide and using Apollo tooling that adds clarity to every change, many iterations of an API can be served from a single endpoint. +1. You run `apollo service:check` locally or in CI. The proposed schema is sent to Engine's schema registry. +1. Engine creates a diff between the local schema and the most recently published schema in the registry. +1. Engine fetches a list of all operations sent to your service in the last day (time window is [configurable](#cli-advanced)). +1. Engine walks through the schema diff change-by-change and compares against the operation list to see if the changes will affect the behavior of any operations. +1. Engine will return the schema diff and indicate any breaking changes found. +1. The CLI will print the output of this check with a link to _view more details in the Engine UI_. -

Field usage

+

Breaking change detection

-Rather than returning extensive amounts of data which might not be necessary, GraphQL allows consumers to specify exactly what data they need. This field-based granularity is valuable and avoids "over-fetching", but also makes it more difficult to understand which parts of the schema are being used. +Engine's cloud service uses an algorithm to detect breaking changes in a schema diff. It follows the following rules to determine which potentially breaking change types should actually _fail_ the `apollo service:check` command and return a non-0 exit code. -To improve the understanding of field usage within an API, Apollo Server extends GraphQL with rich tracing data that demonstrates _how_ a GraphQL field is used and _when_ it's safe to change or eliminate a field. +- **Removals** +
    +
  • `FIELD_REMOVED` A field referenced by at least one operation was removed
  • +
  • `TYPE_REMOVED` A referenced type(scalar, object) was removed
  • +
  • `ARG_REMOVED` A referenced argument was removed
  • +
  • `TYPE_REMOVED_FROM_UNION` A type in a union used by at least one operation was removed
  • +
  • `INPUT_FIELD_REMOVED` A field in an input type used by at least one operation was removed
  • +
  • `VALUE_REMOVED_FROM_ENUM` A value in an enum used by at least one operation was removed
  • +
  • `TYPE_REMOVED_FROM_INTERFACE` An object used by at least one operation was removed from an interface
  • +
+- **Required arguments** +
    +
  • `REQUIRED_ARG_ADDED` Non-nullable argument added to field used by at least one operation
  • +
  • `NON_NULL_INPUT_FIELD_ADDED` Non-null field added to an input object used by at least one operation
  • +
+- **In-place updates** +
    +
  • `FIELD_CHANGED_TYPE` Field used by at least one operation changed return type
  • +
  • `INPUT_FIELD_CHANGED_TYPE` Field in input object referenced in field argument used by at least one operation changed type
  • +
  • `TYPE_CHANGED_KIND` Type used by at least one operation changed, ex: scalar to object or enum to union
  • +
  • `ARG_CHANGED_TYPE` Argument used by at least one operation changed a type
  • +
+- **Type extensions** +
    +
  • `TYPE_ADDED_TO_UNION` New type added to a union used by at least one operation
  • +
  • `TYPE_ADDED_TO_INTERFACE` New interface added to an object used by at least one operation
  • +
+- **Optional arguments** +
    +
  • `ARG_DEFAULT_VALUE_CHANGE` Default value added or changed for argument on a field that is used by at least one operation
  • +
-> For details on how tracing data can be used to avoid shipping breaking changes to clients, check out the schema history tooling in [Apollo Engine](https://www.apollographql.com/platform) which utilizes actual usage data to provide warnings and notices about changes that might break existing clients. +> **Note:** This is not an exhaustive list of all possible schema change types, just _breaking_ change types. Visit the [`graphql` package's repository](https://github.com/graphql/graphql-js/blob/9e404659a15d59c5ce12aae433dd2a636ea9eb82/src/utilities/findBreakingChanges.js#L39) for more details on schema changes types. -Since GraphQL clients only receive exactly what they ask for, adding new fields, arguments, queries, or mutations won't introduce any new breaking changes and these changes can be confidently made without consideration about existing clients or field usage metrics. +A failed `apollo schema:check` command will exit with a non-0 exit code and fail CI checks on purpose! There are actually many cases where it is safe to make a potentially breaking change, as long as the change is made intentionally. -_Field rollover_ is a term given to an API change that's an evolution of a field, such as a rename or a change in arguments. Some of these changes can be really small, resulting in many variations and making an API harder to manage. +Since breaking changes are detected using live traffic, your service will need active metrics for the change algorithm to detect failures. If there are no metrics associated with your service, _all_ changes will be assigned the `NOTICE` severity as opposed to the `FAILURE` severity. -We'll go over these two kinds of field rollovers separately and show how to make these changes safely. +### Validation output -

Renaming or removing a field

+Running a schema validation check is as simple as running `apollo service:check` on the command line from within a service repository that has been configured to be an Apollo project. -When a field is unused, renaming or removing it is as straightforward as it sounds: it can be renamed or removed. However, if a GraphQL deployment doesn't have per-field usage metrics, additional considerations should be made. The following example demonstrates a safe approach to renaming a field. +> **Note:** [Skip ahead](#setup) to the setup section for details on how to configure your project for schema change validation. -Take the following `user` query as an example: +Running the `apollo service:check` command will output the diff of all schema changes found and highlight changes determined to be breaking as `FAILURE`. Here's an example: -```graphql -type Query { - user(id: ID!): User -} +```console +~example$ apollo schema:check + ✔ Loading Apollo Project + ✔ Checking service for changes + + +Change Code Description +─────── ───────────── ────────────────────────────────── +FAILURE FIELD_REMOVED `User.name` was removed +NOTICE FIELD_ADDED `User.friends` was added + + +View full details at: https://engine.apollographql.com/service/example-1234/checks?
``` -We may want to rename it to `getUser` to be more descriptive of what the query is for, like so: +If there are any changes to the schema, `FAILURE` or `NOTICE`, a URL to Engine will be generated with details showing which clients and operations are affected by the changes specifically: -```graphql -type Query { - getUser(id: ID!): User -} +Schema checks page in the Engine UI + +The Service Check page in Engine will have full details on the changes in the diff and which clients are affected by the changes, if any. + +> **Note:** If you [set up your checks on GitHub](#github), the "Details" link in your checks will take you to this special URL as well. + +

Set up schema validation

+ +You will need to be actively sending traces to the Apollo trace warehouse and registering schemas to the Apollo schema registry to properly use schema validation. Follow these guides to set those up: + +1. [Set up trace reporting to Apollo Engine](/docs/platform/setup-analytics.html) (either through Apollo Server 2+ or the Engine proxy). +1. [Set up schema registration in your continuous delivery pipeline](/docs/platform/schema-registry.html). + +For the `apollo schema:check` command to be configured properly, you will also need: + +1. [A `.env` file with an `ENGINE_API_KEY`](/docs/platform/schema-registry.html#Get-your-Engine-API-key). +1. [An `apollo.config.js` file with a `service` configured](/docs/platform/schema-registry.html#Create-an-apollo-config-js-file). + +If you have set up schema registration, your project may already have its `.env` file and `apollo.config.js` file configured. Once you've got these set up, running your schema check is as simple as running: + +```console +apollo service:check ``` -Even if that was the only change, this would be a breaking change for some clients, since those expecting a `user` query would receive error. +The command can be placed in any continuous integration pipeline. To surface results, `apollo` emits an exit code and [integrates with GitHub statuses](#github). The check command validates against traffic from the past day by default, but this time window can be [configured](#cli-advanced) to be a longer range. -To make this change safely, instead of renaming the existing field we can simply add a new `getUser` field and leave the existing `user` field untouched. To prevent code duplication, the resolver logic can be shared between the two fields: +> **Note:** The Apollo CLI will be looking in your Apollo config for a location from which to fetch your local schema and using your ENGINE_API_KEY to authenticate its requests with the Engine service. -```js -const getUserResolver = (root, args, context) => { - context.User.getById(args.id); -}; +

Run validation on each commit

-const resolvers = { - Query: { - getUser: getUserResolver, - user: getUserResolver - } -}; +We highly recommended that you add validation to your continuous integration workflow (e.g. Jenkins, CircleCI, etc.). In doing so, you can detect potential problems automatically and display the results of checks directly on pull requests. + +Here's a example of how to add a schema validation check to CircleCI: + +```yaml line=29 +version: 2 + +jobs: + build: + docker: + - image: circleci/node:8 + + steps: + - checkout + + - run: npm install + + # Start the GraphQL server. If a different command is used to + # start the server, use it in place of `npm start` here. + - run: + name: Starting server + command: npm start + background: true + + # make sure the server has enough time to start up before running + # commands against it + - run: sleep 5 + + # This will authenticate using the `ENGINE_API_KEY` environment + # variable. Configure your endpoint's location in your Apollo config. + - run: npx apollo service:check ``` -

Deprecating a field

+> **Note:** With a GitHub status check, to allow continuous integration to complete without failing early, ignore the exit code of the `apollo service:check` command. The exit code can be ignored by appending `|| echo 'validation failed'` to the command call. -The tactic we used works well to avoid breaking changes, but we still haven’t provided a way for consumers to know that they should switch to using the new field name. Luckily, the GraphQL specification provides a built-in `@deprecated` schema directive (sometimes called decorators in other languages): +

GitHub integration

-``` -type Query { - user(id: ID!): User @deprecated(reason: "renamed to 'getUser'") - getUser(id: ID!): User -} -``` +![GitHub Status View](../img/schema-history/github-check.png) -GraphQL-aware client tooling, like GraphQL Playground and GraphiQL, use this information to assist developers in making the right choices. These tools will: +Like most tools, schema validation is best used when it is integrated directly into the rest of your workflow. If you're using GitHub, you can install the Apollo Engine GitHub app. This will enable Apollo's systems to send a webhook back to your project on each `apollo schema:check`, providing built-in pass/fail status checks on your pull requests. -- Provide developers with the helpful deprecation message referring them to the new name. -- Avoid auto-completing the field. +Go to [https://github.com/apps/apollo-engine](https://github.com/apps/apollo-engine) and click the `Configure` button to install the Apollo Engine integration on the appropriate GitHub profile or organization. -Over time, usage will fall for the deprecated field and grow for the new field. +

Multiple environments

-> Using tools like [Apollo Engine](https://www.apollographql.com/platform), it’s possible to make educated decisions about when to retire a field based on actual usage data through schema analytics. +Product cycles move fast, and it’s common for a schemas to be slightly different across environments as changes make their way through your system. To accommodate for this, schemas can be registered under specific "schema tags +, and checks can be performed against specific "schema tags". -

Non-breaking changes

+schema registry allows each schema to be registered under a “schema tag”. Tags are mostly commonly used to represent environments, but can also be used to represent things like branches and future schemas. Passing the `--tag` flag to `apollo service:check` specifies which schema to compare against, such as `prod` or `staging`. It's common to run checks against multiple different schema tags during continuous integration to ensure that all important deployments are accounted for. Checking multiple tags will result in check statuses similar to: -Sometimes we want to keep a field, but change how clients use it by adjusting its variables. For example, if we had a `getUsers` query that we used to fetch user data based off of a list of user `ids`, but wanted to change the arguments to support a `groupId` to look up users of a group or filter the users requested by the `ids` argument to only return users in the group: +
+![multiple service checks](../img/schema-validation/service-checks.png) +
-```graphql -type Query { - # what we have - getUsers(ids: [ID!]!): [User]! - - # what we want to end up with - getUsers(ids: [ID!], groupId: ID!): [User]! -} -``` - -Since this is an _additive_ change, and doesn't actually change the default behavior of the `getUsers` query, this isn't a breaking change! - -

Breaking changes

- -An example of a breaking change on an argument would be renaming (or deleting) an argument. - -```graphql -type Query { - # What we have. - getUsers(ids: [ID!], groupId: ID!): [User]! - - # What we want to end up with. - getUsers(ids: [ID!], groupIds: [ID!]): [User]! -} -``` - -There's no way to mark an argument as deprecated, but there are a couple options. - -If we wanted to leave the old `groupId` argument active, we wouldn't need to do anything; adding a new argument isn't a breaking change as long as existing functionality doesn't change. - -Instead of supporting it, if we wanted to remove the old argument, the safest option would be to create a new field and deprecate the current `getUsers` field. - -Using an API management tool, like the Apollo platform, it’s possible to determine when usage of an old field has dropped to an acceptable level and remove it. The previously discussed [field rollover](#field-rollover) section gives more info on how to do that. - -Of course, it’s also possible to leave the field in place indefinitely! - -

Checking schema changes with the Apollo CLI

- -To check and see the difference between the current published schema and a new version, run the following command, substituting the appropriate GraphQL endpoint URL and an API key: - -> An API key can be obtained from a service's _Settings_ menu within the [Apollo Engine dashboard](https://engine.apollographql.com/). - -```bash -apollo service:check --key="" --endpoint="http://localhost:4000/graphql" -``` - -> For accuracy, it's best to retrieve the schema from a running GraphQL server (with introspection enabled), though the CLI also reference a local file. See [config options](../platform/apollo-config.html) for more information. - -After analyzing the changes against current usage metrics, Apollo will identify three categories of changes and report them to the developer on the command line or within a GitHub pull-request: - -1. **Failure**: Either the schema is invalid or the changes _will_ break current clients. -2. **Warning**: There are potential problems that may come from this change, but no clients are immediately impacted. -3. **Notice**: This change is safe and will not break current clients. - -

Advanced CLI Usage

+

Adjusting validation parameters

Depending on the requirements of your application, you may want to configure the timeframe to validate operations against. You can do so by providing a `validationPeriod` flag to the CLI. The timeframe will always end at "now", and go back in time by the amount specified. @@ -173,58 +200,3 @@ apollo service:check \ # Only validate against operations that account for at least 3% of total operation volume --queryCountThresholdPercentage=3 ``` - -

GitHub Integration

- -![GitHub Status View](../img/schema-history/github-check.png) - -Schema validation is best used when integrated in a team's development workflow. To make this easy, Apollo integrates with GitHub to provide status checks on pull requests when schema changes are proposed. To enable schema validation in GitHub, follow these steps: - -

Install GitHub application

- -Go to [https://github.com/apps/apollo-engine](https://github.com/apps/apollo-engine) and click the `Configure` button to install the Apollo Engine integration on the appropriate GitHub profile or organization. - -

Run validation on each commit

- -By enabling schema validation in a continuous integration workflow (e.g. CircleCI, etc.), validation can be performed automatically and potential problems can be displayed directly on a pull-request's status checks — providing feedback to developers where they can appreciate it the most. - -To run the validation command, the GraphQL server must have introspection enabled and run the `apollo service:check` command. An example of what this could look like is shown below with a CircleCI config: - -```yaml -version: 2 - -jobs: - build: - docker: - - image: circleci/node:8 - - steps: - - checkout - - - run: npm install - # CircleCI needs global installs to be sudo - - run: sudo npm install --global apollo - - # Start the GraphQL server. If a different command is used to - # start the server, use it in place of `npm start` here. - - run: - name: Starting server - command: npm start - background: true - - # make sure the server has enough time to start up before running - # commands against it - - run: sleep 5 - - # This will authenticate using the `ENGINE_API_KEY` environment - # variable. If the GraphQL server is available elsewhere than - # http://localhost:4000/graphql, set it with `--endpoint=`. - - run: apollo service:check - - # When running on the 'master' branch, publish the latest version - # of the schema to Apollo Engine. - - run: | - if [ "${CIRCLE_BRANCH}" == "master" ]; then - apollo service:push - fi -``` diff --git a/docs/source/resources/graphql-glossary.md b/docs/source/resources/graphql-glossary.md index d27a118..6f8e085 100644 --- a/docs/source/resources/graphql-glossary.md +++ b/docs/source/resources/graphql-glossary.md @@ -3,10 +3,8 @@ title: GraphQL Glossary description: A comprehensive list of important GraphQL words and acronyms --- - When you start diving into the GraphQL ecosystem, you'll probably encounter some unfamiliar terms and phrases along the way. To help you on your journey, we've defined some of the most common GraphQL vocabulary here in this handy cheat sheet. -

Apollo

An open-source implementation of GraphQL that helps you manage data between the cloud and your UI. The Apollo platform is pluggable into your existing architecture and features production-ready tooling across the stack ([Server](https://www.apollographql.com/docs/apollo-server/getting-started.html), [Client](https://www.apollographql.com/docs/react/), and [Engine](https://www.apollographql.com/docs/engine/)).

@@ -104,7 +102,6 @@ type User {

Extensions

Special fields in the Graphql response that allows you to attach extra metadata. [Apollo tracing](https://github.com/apollographql/apollo-server/tree/master/packages/apollo-tracing) is an example of an extension.

-

Field

A unit of data you are asking for in a Schema, which ends up as a field in your JSON response data.

@@ -118,7 +115,6 @@ type Author { `id`, `firstName`, and `lastName` are fields in the Author type above. -

Fragment

A selection set that can be reused in multiple query operations. A [GraphQL fragment](https://www.apollographql.com/docs/react/advanced/fragments.html) is a shared piece of query logic.

@@ -152,6 +148,9 @@ const typeDefs = gql`

GraphQL Playground

An in-browser IDE for GraphQL development and workflow. Added benefits exist such as theme change, automatic schema reloading, HTTP headers configuration, query history and GraphQL subscription support. In addition, it comes [out-of-the-box in Apollo Server 2](https://www.apollographql.com/docs/apollo-server/features/graphql-playground.html).

+

GraphQL Service

+

The server that contains a GraphQL schema and the ability to run it. Services have runtime information, and through features of the Apollo Platform they can send metrics and maintain a history of the schemas that have been run on that service in the past.

+

GraphiQL

An in-browser IDE for GraphQL development.

@@ -184,14 +183,17 @@ mutation AddTodo($type: String!) {

A technique for transforming the response of a query operation before saving it to the store by [Apollo Client's `InMemoryCache`](https://www.apollographql.com/docs/react/advanced/caching.html#normalization). The result is split into individual objects, creating a unique identifier for each object, and storing those objects in a flattened data structure.

```js -import { InMemoryCache, defaultDataIdFromObject } from 'apollo-cache-inmemory'; +import { InMemoryCache, defaultDataIdFromObject } from "apollo-cache-inmemory"; const cache = new InMemoryCache({ dataIdFromObject: object => { switch (object.__typename) { - case 'foo': return object.key; // use `key` as the primary key - case 'bar': return `bar:${object.blah}`; // use `bar` prefix and `blah` as the primary key - default: return defaultDataIdFromObject(object); // fall back to default handling + case "foo": + return object.key; // use `key` as the primary key + case "bar": + return `bar:${object.blah}`; // use `bar` prefix and `blah` as the primary key + default: + return defaultDataIdFromObject(object); // fall back to default handling } } }); @@ -243,21 +245,20 @@ query getHuman { ```js const GET_DOG_PHOTO = gql` - query dog($breed: String!) { - dog(breed: $breed) { - id - displayImage + query dog($breed: String!) { + dog(breed: $breed) { + id + displayImage + } } -}`; +`; export const queryComponent = ({ breed }) => ( {({ loading, error, data }) => { if (loading) return null; - if (error) return 'Error!'; - return ( - - ); + if (error) return "Error!"; + return ; }} ); @@ -285,11 +286,9 @@ const resolvers = { }; ``` -

Schema

A GraphQL [schema](https://www.apollographql.com/docs/apollo-server/essentials/schema.html) is at the center of any GraphQL server implementation and describes the functionality available to the clients which connect to it.

-

Schema Definition Language (SDL)

The syntax for writing GraphQL Schemas. It is otherwise known as Interface Definition Language. It is the lingua franca shared by all for building GraphQL APIs regardless of the programming language chosen.

@@ -315,19 +314,15 @@ type Query {

Schema first development

A [development approach](https://www.apollographql.com/docs/fundamentals/tips.html#schema) for designing and building modern UIs that involves the frontend and backend teams agreeing on a Schema first, which serves as a contract between the UI and the backend before any API engineering happens.

-

Schema registry

A central source of truth for your schema in Apollo Engine. It enables schema registration, schema validation, tracking of detailed schema changes e.g. types added, fields added, fields deprecated and looking up previous versions of schema.

-

Schema versioning

Refers to the need to evolve a schema over time. As a schema evolves, there is a potential for introducing breaking changes to clients. The Apollo CLI assists schema evolution by validating schema changes and checking for breaking changes using Apollo Engine. Read more in the [versioning guide](https://www.apollographql.com/docs/guides/versioning.html).

-

Schema stitching

The process of merging [different schemas into one GraphQL schema](./docs/graphql-tools/schema-stitching.html). These schemas can be local, remote or from third party services. In a microservice-style deployment model, where your data exists across multiple APIs, Schema stitching makes it possible to combine all of them into one schema that can be queried for all the data at once.

-

Subscription

A real-time GraphQL operation. A [Subscription](https://www.apollographql.com/docs/apollo-server/features/subscriptions.html) is defined in a schema like queries and mutations.

@@ -347,7 +342,6 @@ subscription onCommentAdded($repoFullName: String!){

Scalar Type

A type that qualifies the data a GraphQL field resolves. GraphQL ships with some scalar types out of the box; **Int**, **Float**, **String**, **Boolean** and **ID**. However, a [custom scalar](https://www.apollographql.com/docs/graphql-tools/scalars.html#custom-scalars) type such as **Date** can be specified in a GraphQL service implementation.

-

Type System

A collection of types which characterizes the set of data that can be validated, queried and executed on a GraphQL API.

@@ -356,8 +350,8 @@ subscription onCommentAdded($repoFullName: String!){ A value that can be passed to an operation. Variables can be used to fill arguments, or be passed to directives. ```graphql -query GetUser($userId: ID!){ - user(id: $userId){ +query GetUser($userId: ID!) { + user(id: $userId) { firstName } } @@ -368,15 +362,17 @@ In the query above, `userId` is a variable. The variable and its type is declare The userId variable would be passed to the operation by `apollo-client` like this: ```js -client.query({ query: getUserQuery, variables: { userId: 1 }}); +client.query({ query: getUserQuery, variables: { userId: 1 } }); ``` -In `react-apollo` it would be passed like this: +In `react-apollo` it would be passed like this: ```jsx - ... + + {" "} + ...{" "} + ``` -

Whole response caching

A technique used to cache entire results of GraphQL queries. This process improves performance by preventing the fetching of the same results from the server if it has been obtained before. Check out the [Apollo performance guide](../guides/performance.html).

diff --git a/docs/source/tutorial/client.md b/docs/source/tutorial/client.md index 623a4d4..8fec162 100644 --- a/docs/source/tutorial/client.md +++ b/docs/source/tutorial/client.md @@ -130,7 +130,7 @@ Open `src/index.js` and add the following lines of code: _src/index.js_ -```js +```js lines=1,4,6 import { ApolloProvider } from 'react-apollo'; import React from 'react'; import ReactDOM from 'react-dom';