diff --git a/docs/source/old/authentication.md b/docs/source/old/authentication.md
deleted file mode 100644
index 99e30b9..0000000
--- a/docs/source/old/authentication.md
+++ /dev/null
@@ -1,257 +0,0 @@
----
-title: Authentication
-description: How to authorize users and control permissions in your GraphQL API
----
-
-At some point (probably pretty early on) when building a GraphQL endpoint, you’ll probably have to face the question of how to control who can see and interact with the data in your API.
-
-**Authentication** is determining whether a user is logged in or not, and subsequently figuring out _which_ user someone is. **Authorization** is then deciding what the user has permission to do or see.
-
-This article will primarily be focusing on how to set up authorization for your schema once you know about the user trying to make the request, but we’ll go through one example of authentication just to get some _context_ for what we’re doing.
-
-
Putting user info on the context
-
-Before we get into figuring out user permissions, we have to figure out how to recognize a user first. From HTTP headers, to JSON web tokens, there are a number of ways to handle authentication of users, but once you have your user, controlling access looks pretty similar.
-
-We’ll be using a login token in an HTTP authorization header as an example.
-
-```js
-// using apollo-server 2.x
-const { ApolloServer } = require('apollo-server');
-
-const server = new ApolloServer({
- typeDefs,
- resolvers,
- context: ({ req }) => {
- // get the user token from the headers
- const token = req.headers.authorization || '';
-
- // try to retrieve a user with the token
- const user = getUser(token);
-
- // add the user to the context
- return { user };
- },
-});
-
-server.listen().then(({ url }) => {
- console.log(`🚀 Server ready at ${url}`)
-});
-```
-
-So what’s happening here, exactly? This block of code is setting up a new GraphQL server, using Apollo Server 2.0. This new version of Apollo Server simplifies the API for creating new servers, and has some more intelligent defaults. You can read more about it [here](https://blog.apollographql.com/apollo-server-2-0-30c9bbb4ab5e)!
-
-In this constructor, we pass type definitions and resolvers to the constructor as well as a function to build our `context` object. The `context` object is one that gets passed to every single resolver at every level, so we can access it anywhere in our schema code. It’s where we can store things like data fetchers, database connections, and (conveniently) information about the user making the request.
-
-Since the context is generated again with every new request, we don’t have to worry about cleaning up user data at the end of execution.
-
-The context function here looks at the request headers, pulls off the header named `authorization`, and stores it to a variable. It then calls a `getUser` function with that token, and expects a user to be returned if the token is valid. After that, it returns a context object containing the (potential) user, for all of our resolvers to use.
-
-The specifics of retrieving a user will look different for each method of authentication, but the final part will look about the same every time. The authorization needs for your schema may require you to put nothing more than `{ loggedIn: true }` into context, but also may require an id or roles, like `{ user: { id: 12345, roles: ['user', 'admin'] } }`.
-
-In the next section, we’ll look at ways to use the user information we now have to secure your schema.
-
-
Schema authorization
-
-Once we have information about the user making a request, the most basic thing we can do is deny them the ability to run a query at all based on their roles. This is an all-or-nothing approach to authorization that we’ll start with because it’s the simplest. If you choose to block users like this, no fields will be publicly queryable.
-
-We would want to do this only on very restrictive environments where there is no public access to the schema or any fields, like an internal tool or maybe an independent micro service that we don’t want exposed to the public.
-
-To do this kind of authorization, we can just modify the context function.
-
-```js
-context: ({ req }) => {
- // get the user token from the headers
- const token = req.headers.authorization || '';
-
- // try to retrieve a user with the token
- const user = getUser(token);
-
- // optionally block the user
- // we could also check user roles/permissions here
- if (!user) throw new AuthorizationError('you must be logged in');
-
- // add the user to the context
- return { user };
-},
-```
-
-The only difference from the basic context function is the check for the user. If no user exists or if lookup fails, the function throws an error, and none of the query gets executed.
-
-
Authorization in resolvers
-
-Schema authorization may be useful in specific instances, but more commonly, GraphQL schemas will have some fields that need to be public. An example of this would be a news site that wants to show article previews to anyone, but restrict the full body of articles to paying customers only.
-
-Luckily, GraphQL offers very granular control over data. In GraphQL servers, individual field resolvers have the ability to check user roles and make decisions as to what to return for each user. In the previous sections, we saw how to attach user information to the context object. In the rest of the article, we’ll discuss how to use that context object.
-
-For our first example, let’s look at a resolver that’s only accessible with a valid user:
-
-```js
-users: (root, args, context) => {
- // In this case, we'll pretend there is no data when
- // we're not logged in. Another option would be to
- // throw an error.
- if (!context.user) return [];
-
- return ['bob', 'jake'];
-}
-```
-
-This example is a field in our schema named `users` that returns a list of users’ names. The `if` check on the first line of the function looks at the `context` generated from our request, checks for a `user` object, and if one doesn’t exist, returns `null` for the whole field.
-
-One choice to make when building out our resolvers is what an unauthorized field should return. In some use cases, returning `null` here is perfectly valid. Alternatives to this would be to return an empty array, `[]` or to throw an error, telling the client that they’re not allowed to access that field. For the sake of simplicity, we just returned `[]` in this example.
-
-Now let’s expand that example a little further, and only allow users with an `admin` role to look at our user list. After all, we probably don’t want just anyone to have access to all our users.
-
-```js
-users: (root, args, context) => {
- if (!context.user || !context.user.roles.includes('admin')) return null;
- return context.models.User.getAll();
-}
-```
-
-This example looks almost the same as the previous one, with one addition: it expects the `roles` array on a user to include an `admin` role. Otherwise, it returns `null`. The benefit of doing authorization like this is that we can short-circuit our resolvers and not even call lookup functions when we don’t have permission to use them, limiting the possible errors that could expose sensitive data.
-
-Because our resolvers have access to everything in the context, an important question we need to ask is how much information we want in the context. For example, we don’t need the user’s id, name, or age (at least not yet). It’s best to keep things out of the context until they’re needed, since they’re easy to add back in later.
-
-
Authorization in data models
-
-As our server gets more complex, there will probably be multiple places in the schema that need to fetch the same kind of data. In our last example, you may have noticed the return array was replaced with a call to `context.models.User.getAll()`.
-
-Since the very beginning, [we’ve recommended](https://www.apollographql.com/docs/graphql-tools/connectors.html) moving the actual data fetching and transformation logic from resolvers to centralized Model objects that each represent a concept from your application: User, Post, etc. This allows you to make your resolvers a thin routing layer, and put all of your business logic in one place.
-
-For example, a model file for `User` would include all the logic for operating on users, and may look something like…
-
-```js
-export const User = {
- getAll: () => { /* fetching/transform logic for all users */ },
- getById: (id) => { /* fetching/transform logic for a single user */ },
- getByGroupId: (id) => { /* fetching/transform logic for a group of users */ },
-};
-```
-
-In the following example, our schema has multiple ways to request a single user…
-
-```js
-type Query {
- user (id: ID!): User
- article (id: ID!): Article
-}
-
-type Article {
- author: User
-}
-
-type User {
- id: ID!
- name: String!
-}
-```
-
-Rather than having the same fetching logic for a single user in two separate places, it usually makes sense to move that logic to the model file. You may have guessed, with all this talk of model files in an authorization article, that authorization is another great thing to delegate to the model, just like data fetching. You would be right.
-
-**Delegating authorization to models**
-
-You may have noticed that our models also exist on the context, alongside the user object we added earlier. We can add the models to the context in exactly the same way as we did the user.
-
-```js
-context: ({ req }) => {
- // get the user token from the headers
- const token = req.headers.authentication || '';
-
- // try to retrieve a user with the token
- const user = getUser(token);
-
- // optionally block the user
- // we could also check user roles/permissions here
- if (!user) throw new AuthorizationError('you must be logged in to query this schema');
-
- // add the user to the context
- return {
- user,
- models: {
- User: generateUserModel({ user }),
- ...
- }
- };
-},
-```
-
-Starting to generate our models with a function requires a small refactor, that would leave our User model looking something like this:
-
-```js
-export const generateUserModel = ({ user }) => ({
- getAll: () => { /* fetching/transform logic for all users */ },
- getById: (id) => { /* fetching/transform logic for a single user */ },
- getByGroupId: (id) => { /* fetching/transform logic for a group of users */ },
-});
-```
-
-Now any model method in `User` has access to the same `user` information that resolvers already had, allowing us to refactor the `getAll` function to do the permissions check directly rather than having to put it in the resolver:
-
-```js
-getAll: () => {
- if(!user || !user.roles.includes('admin') return null;
- return fetch('http://myurl.com/users');
-}
-```
-
-
Authorization via Custom Directives
-
-Another way to go about authorization is via GraphQL Schema Directives. A directive is an identifier preceded by a `@` character, optionally followed by a list of named arguments, which can appear after almost any form of syntax in the GraphQL query or schema languages.
-
-Check out this example of an authorization directive:
-
-```js
-const typeDefs = `
- directive @auth(requires: Role = ADMIN) on OBJECT | FIELD_DEFINITION
-
- enum Role {
- ADMIN
- REVIEWER
- USER
- }
-
- type User @auth(requires: USER) {
- name: String
- banned: Boolean @auth(requires: ADMIN)
- canPost: Boolean @auth(requires: REVIEWER)
- }
-`
-```
-
-The `@auth` directive can be called directly on the type, or on the fields if you want to limit access to specific fields as shown in the example above. The logic behind authorization is hidden away in the directive implementation.
-
-One way of implementing the `@auth` directive is via the [SchemaDirectiveVisitor](https://www.apollographql.com/docs/graphql-tools/schema-directives.html) class from [graphql-tools](https://github.com/apollographql/graphql-tools). Ben Newman covered creating a sample `@deprecated` and `@rest` directive in this [excellent article](https://blog.apollographql.com/reusable-graphql-schema-directives-131fb3a177d1). You can draw inspiration from these examples.
-
-
-
Authorization outside of GraphQL
-
-If you’re using a REST API that has built-in authorization, like with an HTTP header, you have one more option. Rather than doing any authentication or authorization work in the GraphQL layer (in resolvers/models), it’s possible to simply pass through the headers or cookies to your REST endpoint and let it do the work.
-
-Here’s an example:
-
-```js
-// src/server.js
-context: ({ req }) => {
- // pass the request information through to the model
- return {
- user,
- models: {
- User: generateUserModel({ req }),
- ...
- }
- };
-},
-```
-
-```js
-// src/models/user.js
-export const generateUserModel = ({ req }) => ({
- getAll: () => {
- return fetch('http://myurl.com/users', { headers: req.headers });
- },
-});
-```
-
-If your REST endpoint is already backed by some form of authorization, this cuts down a lot of the logic that needs to get built in the GraphQL layer. This can be a great option when building a GraphQL API over an existing REST API that has everything you need already built in.
diff --git a/docs/source/old/file-uploads.md b/docs/source/old/file-uploads.md
deleted file mode 100644
index 5e89275..0000000
--- a/docs/source/old/file-uploads.md
+++ /dev/null
@@ -1,256 +0,0 @@
----
-title: File uploads
-description: Implementing file uploads in GraphQL apps
----
-
-File uploads are a requirement for many applications. Apollo Server supports the [GraphQL multipart request specification](https://github.com/jaydenseric/graphql-multipart-request-spec) for uploading files as mutation arguments using [apollo-upload-server](https://github.com/jaydenseric/apollo-upload-server).
-
-## File upload with default options
-
-Apollo Server automatically adds the `Upload` scalar to the schema when you are not setting the schema manually.
-
-```js
-const { ApolloServer, gql } = require('apollo-server');
-
-const typeDefs = gql`
- type File {
- filename: String!
- mimetype: String!
- encoding: String!
- }
-
- type Query {
- uploads: [File]
- }
-
- type Mutation {
- singleUpload(file: Upload!): File!
- }
-`;
-
-const resolvers = {
- Query: {
- files: () => {
- // Return the record of files uploaded from your DB or API or filesystem.
- }
- },
- Mutation: {
- async singleUpload(parent, { file }) {
- const { stream, filename, mimetype, encoding } = await file;
-
- // 1. Validate file metadata.
-
- // 2. Stream file contents into local filesystem or cloud storage:
- // https://nodejs.org/api/stream.html
-
- // 3. Record the file upload in your DB.
- // const id = await recordFile( … )
-
- return { stream, filename, mimetype, encoding };
- }
- },
-};
-
-const server = new ApolloServer({
- typeDefs,
- resolvers,
-});
-
-server.listen().then(({ url }) => {
- console.log(`🚀 Server ready at ${url}`);
-});
-```
-
-## File upload with schema param
-
-In a situation where a schema is set manually using `makeExecutableSchema` and passed to the `ApolloServer` constructor using the schema params, add the `Upload` scalar to the type definitions and `Upload` to the resolver as shown in the example below:
-
-```js
-const { ApolloServer, makeExecutableSchema, gql, GraphQLUpload } = require('apollo-server');
-
-const typeDefs = gql`
- scalar Upload
- type File {
- filename: String!
- mimetype: String!
- encoding: String!
- }
-
- type Query {
- uploads: [File]
- }
-
- type Mutation {
- singleUpload(file: Upload!): File!
- }
-`;
-
-const resolvers = {
- Upload: GraphQLUpload,
- Query: {
- files: () => {
- // Return the record of files uploaded from your DB or API or filesystem.
- }
- },
- Mutation: {
- async singleUpload(parent, { file }) {
- const { stream, filename, mimetype, encoding } = await file;
-
- // 1. Validate file metadata.
-
- // 2. Stream file contents into local filesystem or cloud storage:
- // https://nodejs.org/api/stream.html
-
- // 3. Record the file upload in your DB.
- // const id = await recordFile( … )
-
- return { stream, filename, mimetype, encoding };
- }
- },
-};
-
-const schema = makeExecutableSchema({ typeDefs, resolvers });
-
-const server = new ApolloServer({
- schema,
-});
-
-server.listen().then(({ url }) => {
- console.log(`🚀 Server ready at ${url}`);
-});
-```
-
-
-## Scalar Upload
-
-The `Upload` type automatically added to the schema by Apollo Server resolves an object containing the following:
-
-- `stream`
-- `filename`
-- `mimetype`
-- `encoding`
-
-
-### File upload options
-
-The `ApolloServer` constructor supports the following configuration properties. They are:
-
-- `maxFieldSize`: represents allowed non-file multipart form field size in bytes.
-- `maxFileSize`: represents the allowed file size in bytes.
-- `maxFiles`: represents the allowed number of files. It can accept as many files as possible.
-
-
-## Client setup
-
-From the client side, you need to install the `apollo-upload-client` package. It enables file uploads via GraphQL mutations.
-
-```sh
-npm install apollo-upload-client
-```
-
-You will then need to initialize your [Apollo Client](https://apollographql.com/docs/link#apollo-client) instance with a terminating [Apollo Link](https://apollographql.com/docs/link), created by calling [`createUploadlink`](https://github.com/jaydenseric/apollo-upload-client#function-createuploadlink). For example:
-
-```js
-import { ApolloClient } from 'apollo-client';
-import { InMemoryCache } from 'apollo-cache-inmemory';
-import { createUploadLink } from 'apollo-upload-client';
-
-const client = new ApolloClient({
- cache: new InMemoryCache(),
- link: createUploadLink(),
-});
-```
-
-> Note: [Apollo Boost](https://www.apollographql.com/docs/react/essentials/get-started.html#apollo-boost) does not support Apollo Link overrides, so if you're using Apollo Boost and want to use `apollo-upload-client`, you will need to switch to the full version of Apollo Client. See the [Apollo Boost migration](https://www.apollographql.com/docs/react/advanced/boost-migration.html) docs for help migrating from Apollo Boost to Apollo Client.
-
-_File uploads example from the client for a single file:_
-
-```js
-import gql from 'graphql-tag';
-import { Mutation } from 'react-apollo';
-
-export const UPLOAD_FILE = gql`
- mutation uploadFile($file: Upload!) {
- uploadFile(file: $file) {
- filename
- }
- }
-`;
-
-const uploadFile = () => {
- return (
-
- {uploadFile => (
-
- validity.valid && uploadFile({ variables: { file } });
- }
- />
- )}
-
- );
-};
-```
-
-_File uploads example from the client for multiple files:_
-
-```js
-import gql from 'graphql-tag';
-import { Mutation } from 'react-apollo';
-
-export const UPLOAD_MULTIPLE_FILES = gql`
- mutation uploadMultipleFiles($files: [Upload!]!) {
- uploadMultipleFiles(files: $files) {
- filename
- }
- }
-`;
-
-const uploadMultipleFiles = () => {
- return (
-
- {uploadFile => (
-
- validity.valid && uploadMultipleFiles({ variables: { files } });
- }
- />
- )}
-
- );
-};
-```
-
-_Blob example from the client:_
-
-```js
-import gql from 'graphql-tag'
-
-// Apollo Client instance
-import client from './apollo'
-
-const file = new Blob(['Foo.'], { type: 'text/plain' })
-
-// Optional, defaults to `blob`
-file.name = 'bar.txt'
-
-client.mutate({
- mutation: gql`
- mutation($file: Upload!) {
- uploadFile(file: $file) {
- filename
- }
- }
- `,
- variables: { file }
-})
-```
-
-Use [FileList](https://developer.mozilla.org/en/docs/Web/API/FileList), [File](https://developer.mozilla.org/en/docs/Web/API/File), [Blob](https://developer.mozilla.org/en/docs/Web/API/Blob) instances anywhere within query or mutation input variables to send a GraphQL multipart request.
-
-**Jayden Seric**, author of [apollo-upload-client](https://github.com/jaydenseric/apollo-upload-client) has [an example app on GitHub](https://github.com/jaydenseric/apollo-upload-examples/tree/master/app). It's a web app using [Next.js](https://github.com/zeit/next.js/), [react-apollo](https://github.com/apollographql/react-apollo), and [apollo-upload-client](https://github.com/jaydenseric/apollo-upload-client).
\ No newline at end of file
diff --git a/docs/source/old/security.md b/docs/source/old/security.md
deleted file mode 100644
index 11419ef..0000000
--- a/docs/source/old/security.md
+++ /dev/null
@@ -1,81 +0,0 @@
----
-title: Security
-description: Building a secure, safe GraphQL server
----
-
-Apollo Server is a safer way to build applications thanks to GraphQL's strong typing and the conversion of raw operations into a trusted syntax tree. By validating each part of an operation, GraphQL is mostly exempt from injection-attacks which might be of concern on other platforms.
-
-This guide will discuss additional security measures which further harden the excellent foundation which GraphQL is already built upon. While Apollo Server will enable some additional protections automatically, others require attention on the part of the developer.
-
-
Introspection in production
-
-Introspection is a powerful tool to have enabled during development and allows developers to get real-time visibility of a GraphQL server's capabilities. In production, this insight might be less desirable, especially if the API is not being offered as a “public” API.
-
-For security, Apollo Server introspection is automatically disabled when the `NODE_ENV` is set to `production` or `testing`. For those wishing to allow introspection, the functionality can be explicitly enabled by setting `introspection` to `true` on the `ApolloServer` constructor options.
-
-Of course, no system should rely solely on so-called "security through obscurity" and this practice should be combined with other security techniques like _open security_ and _security by design_.
-
-
Injection prevention
-
-As we build out our schema, it may be tempting to allow for “shortcut arguments” to creep in. This creative repurposing of fields might seem like a good idea at the time, but it often creates unnecessary security risks. This most commonly happens on mutation inputs or when attempting to use a simple “filter”-type field to do generic work, as demonstrated in this example:
-
-```graphql
-query OhNo {
- users(filter: "id = 1;' sql injection goes here!") {
- id
- }
-}
-
-mutation Dang {
- updateUser(user: { firstName: "James", id: 1 }) {
- success
- }
-}
-```
-
-In the first `query` operation we are passing a filter that is a database filter directly as a string. Since this value is passed directly to the data storage engine and the input value itself can be manipulated by a malicious user, this opens the door to a SQL injection attack.
-
-In the second `mutation` operation an arbitrary `id` value is being passed which could allow a bad actor to update information for another user by simply manipulating the mutation with a different user ID. This can happen if a generic `input` type has been used inappropriately, as in the following example:
-
-```graphql
-# Used for creating and updating a user!
-input UserInput {
- id: Int
- firstName: String
-}
-
-type Mutation {
- createUser(user: UserInput): User
- updateUser(user: UserInput): User
-}
-```
-
-The fix for both of these scenarios is to create more explicit arguments, with each serving the appropriate purpose, and allow Apollo Server to prune incorrectly typed values during validation. Additionally, care should be taken to **never** pass raw values from clients into a datastore.
-
-Of course, any of the above scenarios can occur in any API implementations if proper precautions are not taken, and GraphQL is no different in this regard.
-
-
Denial-of-Service (DoS) Protection
-
-Apollo Server is a Node.js application and standard precautions should be taken in order to avoid Denial-of-Service (DoS) attacks.
-
-Since GraphQL involves the traversal of a graph in which circular relationships of arbitrary depths might be accessible, some additional precautions can be taken to limit the risks of complexity attacks where bad actors could craft expensive operations and lock up resources indefinitely.
-
-There are two common mitigation techniques and they can be enabled together:
-
-
Operation safe-listing
-
-By hashing the potential operations a client is expected to send (e.g. based on field names) and storing these "permitted" hashes on the server (or a shared cache), it becomes possible to check incoming operations against the permitted hashes and skip execution if the hash is not allowed.
-
-Since many consumers of non-public APIs have their operations statically defined within their source code, this technique is often sufficient and is best implemented as an automated deployment step.
-
-Future versions of Apollo Server and Apollo Engine will make it easier to maintain a list of allowed operations, though complexity limits (discussed in the next section) are a very reasonable solution which can provide similar protection.
-
-
Complexity limits
-
-These can be used to limit the use of queries which, for example, request a list of books including the authors of each book, plus the books of those authors, and _their_ authors, and so on. By limiting operations to an application-defined depth of "_n_", these can be prevented.
-
-We suggest implementing complexity limits using community-provided packages like [graphql-depth-limit](https://github.com/stems/graphql-depth-limit) and [graphql-validation-complexity](https://github.com/4Catalyzer/graphql-validation-complexity).
-
-
Additional resources
-
-> For additional information on securing a GraphQL server deployment, check out [Securing your GraphQL API from malicious queries](https://blog.apollographql.com/securing-your-graphql-api-from-malicious-queries-16130a324a6b) by Spectrum co-founder, Max Stoiber.
diff --git a/docs/source/old/state-management.md b/docs/source/old/state-management.md
deleted file mode 100644
index 57f9755..0000000
--- a/docs/source/old/state-management.md
+++ /dev/null
@@ -1,121 +0,0 @@
----
-title: State management
-description: Managing your local and remote state in a GraphQL world
----
-
-Not only is state management one of the most important aspects of building the front-end for your application, it's also one of the most challenging. With a REST and Redux workflow, you're writing action creators, reducers, and selectors for each network request. For a production-level app, you're also juggling several middleware packages for features like optimistic updates and manually normalizing your data.
-
-With a GraphQL and Apollo workflow, you just write queries and let Apollo Client take care of the rest. Apollo Client normalizes and caches your data out of the box with zero configuration. It also enables you to execute complicated features such as optimistic UI, polling, and pagination with only a few lines of code.
-
-If we're using Apollo Client to manage our remote data, then what do we do with local data such as boolean flags and device API information that we'd like to access globally? This is where [`apollo-link-state`](/docs/react/essentials/local-state.html) comes in, our solution for local state management that allows you to use your Apollo cache as the single source of truth for data in your application. We recommend managing all of your local and remote data with Apollo Client so GraphQL becomes a unified interface to all of your application's data.
-
-The following sections outline some tips to help you make the most of your transition to managing all of your state with Apollo Client.
-
-
Colocate queries with components
-
-When you first start building `Query` components for your GraphQL data, it can be tempting to dump all of your queries in one file similar to how developers using Redux put all of their reducers in a single file. Instead, we recommend that you colocate your GraphQL queries with the `Query` components that are using them. One of the greatest strengths of GraphQL is its declarative approach to data fetching, which you lose when you have to switch back to another file in order to determine what the shape of your data prop looks like:
-
-```jsx
-const GET_DOG_PHOTO = gql`
- query dog($breed: String!) {
- dog(breed: $breed) {
- id
- displayImage
- }
- }
-`;
-
-const DogPhoto = ({ breed }) => (
-
- {({ loading, error, data }) => {
- if (loading) return null;
- if (error) return `Error!: ${error}`;
-
- return (
-
- );
- }}
-
-);
-```
-
-In this example, we place our `GET_DOG_PHOTO` query next to our `DogPhoto` component and wrap it with the `gql` function. Now in the render prop function for `Query`, we know exactly what properties live on `data` and can use them to render our UI.
-
-
Move data transformation to the backend
-
-Your GraphQL schema should always reflect how you're consuming the data on the front-end. This is why we recommend that [product teams own the design](../fundamentals/tips.html#schema) of their GraphQL schema. Shifting to this mentality is a bit of a departure from REST, where front-end developers consume APIs dictated by the backend team and often have to filter and sort the data into the shape their UI components expect.
-
-If you find yourself sorting or filtering the data you receive back from your GraphQL API, it's probably a sign that you need to move that logic to your resolvers instead. Moving filtering and sorting logic to the backend ensures that you can share it across platforms easily instead of duplicating these efforts for every client.
-
-**Instead of this:**
-```jsx
-const GET_MOVIES = gql`
- {
- movies {
- id
- title
- popularity
- score
- }
- }
-`;
-
-const PopularMovies = () => (
-
- {({ loading, error, data }) => {
- if (loading) return null;
- if (error) return `Error!: ${error}`;
-
- const popularMovies = data.movies.sort((a, b) => {
- return b.popularity - a.popularity;
- });
-
- return
- }}
-
-);
-```
-
-**Do this:**
-
-```jsx
-const GET_MOVIES = gql`
- {
- movies(sort: POPULARITY) {
- id
- title
- popularity
- score
- }
- }
-`;
-
-const PopularMovies = () => (
-
- {({ loading, error, data }) => {
- if (loading) return null;
- if (error) return `Error!: ${error}`;
-
- return
- }}
-
-);
-```
-
-
Combine local and remote data
-
-With `apollo-link-state`, you can add virtual fields to your remote data seamlessly and query them from your components by specifying a `@client` directive. In this example, we’re querying the client-only field isLiked alongside our server data. Your components are made up of local and remote data, now your queries can be too! This is one of the main advantages for using Apollo Client to manage all of your application's data.
-
-```graphql
-const GET_DOG = gql`
- query getDogByBreed($breed: String!) {
- dog(breed: $breed) {
- images {
- url
- id
- isLiked @client
- }
- }
- }
-`;
-```
\ No newline at end of file
diff --git a/docs/source/resources/apollo-config.md b/docs/source/platform/apollo-config.md
similarity index 98%
rename from docs/source/resources/apollo-config.md
rename to docs/source/platform/apollo-config.md
index 85c7072..6062c57 100644
--- a/docs/source/resources/apollo-config.md
+++ b/docs/source/platform/apollo-config.md
@@ -1,6 +1,6 @@
---
-title: Apollo Config
-description: Configuration options for Apollo projects
+title: Configuring Apollo projects
+description: How to configure Apollo VS Code and CLI with apollo.config.js
---
Apollo projects are configured using an `apollo.config.js` file at the root of the project. This config file powers [editor integrations](../platform/editor-plugins.html) and the [Apollo CLI](https://www.npmjs.com/package/apollo). The configuration file how Apollo projects are setup. There are two types of projects, `client` and `service` which can be in the same configuration file if necessary.
diff --git a/docs/source/platform/client-awareness.md b/docs/source/platform/client-awareness.md
index 3561296..5973ba9 100644
--- a/docs/source/platform/client-awareness.md
+++ b/docs/source/platform/client-awareness.md
@@ -1,4 +1,125 @@
---
title: Identifying clients
-description: How to configure Apollo Engine for client awareness
----
\ No newline at end of file
+description: What is client awareness and how to add it to the Apollo Platform
+---
+
+Client identity is central to the Apollo Platform and enables tracking how all
+the consumers use the data graph. The Apollo Platform allows **segmenting usage
+data by client name and version**. Filtering by client provides a
+**field-level understanding** of how the consumers interact with the GraphQL api in
+real-time. In addition to per-client metrics, understanding this granular
+detail informs **how the GraphQL schema can evolve** and react to new **client
+releases**.
+
+
+
+Often a GraphQL api is used by multiple consumers with different frequencies,
+subselections, and permissions. The Apollo Platform allows tagging all reported
+metrics with client name and version, which enables filtering on a specific
+client or set of clients across different stacks. This segmentation provides:
+
+1. Queries and fields used by each clients
+2. Client importance based on relative usage
+
+## Setup
+
+By default, Apollo Server >=2.2.3 looks at the request headers for `apollographql-client-name` and `apollographql-client-version`.
+With Apollo Client >2.4.6, we set the `name` and `version` inside of the `ApolloClient` constructor:
+
+```js line=8-9
+import { ApolloClient } from 'apollo-client';
+import { HttpLink } from 'apollo-link-http';
+
+const client = new ApolloClient({
+ link: new HttpLink({
+ uri: 'http://localhost:4000/graphql',
+ })
+ name: 'insert your client name',
+ version: 'insert your client version',
+});
+```
+
+If you are not using Apollo Server and would like to gain client awareness,
+please reach out to opensource [at] apollographql.com to work with us to add
+support to your server language of choice.
+
+## Use Cases
+
+### Isolating Clients
+
+Filtering queries by client enables isolation of issues that affect a portion
+of all clients. In the opposite sense, if a client becomes problematic, such as
+requesting expensive fields or using deprecated fields, the Apollo Platform
+enables tracking down the faulty client to start solving the issue with the
+owner. When changing, replacing, or deprecating a field in the api, the client
+metadata enables quickly identifying the client-side changes that need to
+occur to completely remove the field.
+
+
+
+### Cutover
+
+Similarly to deprecation, additions to a GraphQL api often mean that clients will change. These modifications can be done incrementally or discretely during a cutover period. The cutover period and time immediately following change the utilization of the GraphQL api drastically and can expose some unexpected behavior. Filtering by client version enables monitoring the health of a release in real-time. The following demonstrates a cutover from one backend to another.
+
+
+
+
+## Advanced Setup
+
+Client awareness is a full stack solution that threads client information from
+the consumer to server, so we can configure the client and server.
+
+### Client
+
+The client or consumer of the GraphQL api is responsible for including the
+information in a way that the server understands. In this case, we add the
+client name and version to the http headers:
+
+```js line=8-11
+import { ApolloClient } from 'apollo-client';
+import { HttpLink } from 'apollo-link-http';
+import { ApolloLink } from 'apollo-link';
+
+const client = new ApolloClient({
+ link: new HttpLink({
+ uri: 'http://localhost:4000/graphql',
+ headers: {
+ 'client-name': 'Web',
+ 'client-version': '1',
+ }
+ }),
+});
+```
+
+### Server
+
+The server is responsible for collecting and assigning the client information
+to a request. To provide metrics to the Apollo Platform, pass a
+`generateClientInfo` function into the `ApolloServer` constructor. The
+following checks the headers and provides a fallback.
+
+```js line=8-16
+const { ApolloServer } = require('apollo-server');
+
+const server = new ApolloServer({
+ typeDefs,
+ resolvers,
+ engine: {
+ apiKey: 'YOUR API KEY HERE',
+ generateClientInfo: ({
+ request
+ }) => {
+ const headers = request.headers;
+ return {
+ clientName: headers && headers['client-name'] || 'Unknown Client',
+ clientVersion: headers && headers['client-version'] || 'Unversioned',
+ };
+ },
+ }
+});
+
+server.listen().then(({ url }) => {
+ console.log(`🚀 Server ready at ${url}`);
+});
+```
+
diff --git a/docs/source/platform/schema-design.md b/docs/source/platform/schema-design.md
deleted file mode 100644
index c3c47e4..0000000
--- a/docs/source/platform/schema-design.md
+++ /dev/null
@@ -1,461 +0,0 @@
----
-title: Schema design
-description: How to structure your GraphQL types, fields, and arguments
----
-
-One of the main aspects of GraphQL is that it allows you to describe the space of data available in your system with a strongly typed schema. While GraphQL makes it possible to evolve your API over time without breaking your clients, it's always easier if you think about some schema design decisions up front to reduce the amount of refactoring you need to do later.
-
-This article details some practices around schema design which will help you design a great GraphQL API to stand the test of time.
-
-
Designing for client needs
-
-GraphQL schemas are at their best when they are designed around the needs of client applications. When a team is building their first GraphQL schema, they might be tempted to create literal mappings on top of existing database collections or tables using CRUD-like root fields. While this literal database-to-schema mapping may be a fast way to get up and running, we strongly suggest avoiding it and instead building the schema around based on how the GraphQL API will be used by the front-end.
-
-If a database has fields or relationships that the client doesn't yet need, don’t include them in the schema up front. Adding fields later is much easier than removing them, so add fields to your API as your clients need them rather than exposing all of the possible data up front. This is especially useful because GraphQL allows you to create associations between your data that don't exist in the underlying data, enabling you to move complex data manipulation logic out of your clients.
-
-For example, let's say you want to create a view that lists some events, their locations, and the weather at that location. In that case, you might want to do a query like this:
-
-```graphql
-query EventList {
- upcomingEvents {
- name
- date
- location {
- name
- weather {
- temperature
- description
- }
- }
- }
-}
-```
-
-The desire to display this data could inform the design of a schema like the following:
-
-```graphql
-type Query {
- upcomingEvents: [Event]
- # Other fields, etc
-}
-
-type Event {
- name: String
- date: String
- location: Location
-}
-
-type Location {
- name: String
- weather: WeatherInfo
-}
-
-type WeatherInfo {
- temperature: Float
- description: String
-}
-```
-
-This doesn't necessarily need to match the data returned from a single REST endpoint or database. For example, if you have a REST endpoint exposing a list of events and their locations, but not weather information, you would just need to fetch the weather information from a second endpoint (or even a 3rd party API) in your resolvers. This way, you can design a schema that will allow your frontend to be as simple as possible, without limiting yourself to the exact shape of data that's in your underlying data sources.
-
-
Style conventions
-
-The GraphQL specification is flexible and doesn't impose specific naming guidelines. However, in order to facilitate development and continuity across GraphQL deployments, it's useful to have a general set of conventions. We suggest the following:
-
-* **Fields** should be named in `camelCase`, since the majority of consumers will be client applications written in JavaScript, Java, Kotlin, or Swift, all of which recommend `camelCase` for variable names.
-* **Types**: should be `PascalCase`, to match how classes are defined in the languages above.
-* **Enums**: should have their type name in `PascalCase`, and their value names in `ALL_CAPS`, since they are similar to constants.
-
-If you use the conventions above, you won't need to have any extra logic in your clients to convert names to match the conventions of these languages.
-
-
Utilizing interfaces
-
-Interfaces are a powerful way to build and use GraphQL schemas through the use of _abstract types_. Abstract types can't be used directly in schema, but can be used as building blocks for creating explicit types.
-
-Consider an example where different types of books share a common set of attributes, such as _text books_ and _coloring books_. A simple foundation for these books might be represented as the following `interface`:
-
-```graphql
-interface Book {
- title: String
- author: Author
-}
-```
-
-We won't be able to directly use this interface to query for a book, but we can use it to implement concrete types. Imagine a screen within an application which needs to display a feed of all books, without regard to their (more specific) type. To create such functionality, we could define the following:
-
-```graphql
-type TextBook implements Book {
- title: String
- author: Author
- classes: [Class]
-}
-
-type ColoringBook implements Book {
- title: String
- author: Author
- colors: [Color]
-}
-
-type Query {
- schoolBooks: [Book]
-}
-```
-
-In this example, we've used the `Book` interface as the foundation for the `TextBook` and `ColoringBook` types. Then, a `schoolBooks` field simply expresses that it returns a list of books (i.e. `[Book]`).
-
-Implementing the book feed example is now simplified since we've removed the need to worry about what kind of `Book`s will be returned. A query against this schema, which could return _text books_ and _coloring_ books, might look like:
-
-```graphql
-query GetBooks {
- schoolBooks {
- title
- author
- }
-}
-```
-
-This is really helpful for feeds of common content, user role systems, and more!
-
-Furthermore, if we need to return fields which are only provided by either `TextBook`s or `ColoringBook`s (not both) we can request fragments from the abstract types in the query. Those fragments will be filled in only as appropriate; in the case of the example, only coloring books will be returned with `colors`, and only textbooks will have `classes`:
-
-```graphql
-query GetBooks {
- schoolBooks {
- title
- ... on TextBook {
- classes {
- name
- }
- }
- ... on ColoringBook {
- colors {
- name
- }
- }
- }
-}
-```
-
-
Designing mutations
-
-The `Mutation` type is a core type in GraphQL which specializes in _modifying_ data, which contrasts the `Query` type used for _fetching_ data.
-
-Unlike REST, where the behavior can be more ad-hoc, the `Mutation` type is designed with the expectation that there will be a response object. This ensures that the client receives the most current data without a subsequent round-trip re-query.
-
-A mutation for updating the age of a `User` might look like this:
-
-```graphql
-type Mutation {
- updateUserAge(id: ID!, age: Int!): User
-}
-
-type User {
- id: ID!
- name: String!
- age: Int!
-}
-```
-
-With this definition, the following mutation becomes possible:
-
-```graphql
-mutation updateMyUser {
- updateUserAge(id: 1, age: 25){
- id
- age
- name
- }
-}
-```
-
-Once executed by the server, the response returned to the client might be:
-
-```json
-{
- "data": {
- "updateUserAge": {
- "id": "1",
- "age": "25",
- "name": "Jane Doe"
- }
- }
-}
-```
-
-While it's not mandatory to return the object which has been updated, the inclusion of the updated information allows the client to confidently update its local state without performing additional requests.
-
-As with queries, it's best to design mutations with the client in mind and in response to a user's action. In simple cases, this might only result in changes to a single document, however in many cases there will be updates to multiple documents from different resources, for example, a `likePost` mutation might update the total likes for a user as well as their post.
-
-In order to provide a consistent shape of response data, we recommend adopting a pattern which returns a standardized response format which supports returning any number of documents from each resource which was modified. We'll outline a recommended patterns for this in the next section.
-
-
Responses
-
-GraphQL mutations can return any information the developer wishes, but designing mutation responses in a consistent and robust structure makes them more approachable by humans and less complicated to traverse in client code. There are two guiding principles which we have combined into our suggested mutation response structure.
-
-First, while mutations might only modify a single resource type, they often need to touch several at a time. It makes sense for this to happen in a single round-trip to the server and this is one of the strengths of GraphQL! When different resources are modified, the client code can benefit from having updated fields returned from each type and the response format should support that.
-
-Secondly, mutations have a higher chance of causing errors than queries since they are modifying data. If only a portion of a mutation update succeeds, whether that is a partial update to a single document's fields or a failed update to an entire document, it's important to convey that information to the client to avoid stale local state on the client.
-
-A common way to handle errors during a mutation is to simply `throw` an error. While that's fine, throwing an error in a resolver will return an error for the entire operation to the caller and prevent a more meaningful response. Consider the following mutation example, which tries to update a user's `name` and `age`:
-
-```graphql
-mutation updateUser {
- updateUser(id: 1, user: { age: -1, name: "Foo Bar" }){
- name
- age
- }
-}
-```
-
-With validation in place, this mutation might cause an error since the `age` is a negative value. While it’s possible that the entire operation should be stopped, there’s an opportunity to partially update the user’s record with the new `name` and return the updated record with the `age` left untouched.
-
-Fortunately, the powerful structure of GraphQL mutations accommodates this use case and can return transactional information about the update alongside the records which have been changed which enables client-side updates to occur automatically.
-
-In order to provide consistency across a schema, we suggest introducing a `MutationResponse` interface which can be implemented on every mutation response in a schema and enables transactional information to be returned in addition to the normal mutation response object.
-
-A `MutationResponse` interface would look like this:
-
-```graphql
-interface MutationResponse {
- code: String!
- success: Boolean!
- message: String!
-}
-```
-
-An implementing type would look like this:
-
-```graphql
-type UpdateUserMutationResponse implements MutationResponse {
- code: String!
- success: Boolean!
- message: String!
- user: User
-}
-```
-
-Calling a mutation that returns that `UpdateUserMutationResponse` type would result in a response that looks something like this:
-
-```json
-{
- "data": {
- "updateUser": {
- "code": "200",
- "success": true,
- "message": "User was successfully updated",
- "user": {
- "id": "1",
- "name": "Jane Doe",
- "age": 35
- }
- }
- }
-}
-```
-
-Let’s break this down, field by field:
-
-* `code` is a string representing a transactional value explaining details about the status of the data change. Think of this like an HTTP status code.
-* `success` is a boolean indicating whether the update was successful or not. This allows a coarse check by the client to know if there were failures.
-* `message` is a string that is meant to be a human-readable description of the status of the transaction. It is intended to be used in the UI of the product.
-* `user` is added by the implementing type `UpdateUserMutationResponse` to return back the newly created user for the client to use!
-
-For mutations which have touched multiple types, this same structure can be used to return updated objects from each one. For example, a `likePost` type, which could affect a user's "reputation" and also update the post itself, might implement `MutationResponse` in the following manner:
-
-```graphql
-type LikePostMutationResponse implements MutationResponse {
- code: String!
- success: Boolean!
- message: String!
- post: Post
- user: User
-}
-```
-
-In this response type, we've provided the expectation that both the `user` and the `post` would be returned and an actual response to a `likePost` mutation could be:
-
-```json
-{
- "data": {
- "likePost": {
- "code": "200",
- "success": true,
- "message": "Thanks!",
- "post": {
- "likes": 5040
- },
- "user": {
- "reputation": 11
- }
- }
- }
-}
-```
-
-Following this pattern for mutations provides detailed information about the data that has changed and feedback on whether the operation was successful or not. Armed with this information, developers can easily react to failures within the client
-
-
Input types
-
-Input types are a special type in GraphQL which allows an object to be passed as an argument to both queries and mutations and is helpful when simple scalar types aren't sufficient.
-
-This allows arguments to be structured in an more manageable way, similar to how switching to an `options` argument might be appreciated when `function` arguments become too iterative.
-
-For example, consider this mutation which creates a post along with its accompanying media URLs (e.g. images):
-
-```graphql
-type Mutation {
- createPost(title: String, body: String, mediaUrls: [String]): Post
-}
-```
-
-This could be easier to digest, and the arguments would be easier to re-use within the mutation, by using an `input` type with the relevant fields.
-
-An input type is defined like a normal object type but using the `input` keyword. To introduce an `input` type for this example, we'd do:
-
-```graphql
-type Mutation {
- createPost(post: PostAndMediaInput): Post
-}
-
-input PostAndMediaInput {
- title: String
- body: String
- mediaUrls: [String]
-}
-```
-
-Not only does this facilitate passing the `PostAndMediaInput` around within the schema, it also provides a basis for annotating fields with descriptions which are automatically exposed by GraphQL-enabled tools:
-
-```graphql
-input PostAndMediaInput {
- "A main title for the post"
- title: String
- "The textual body of the post."
- body: String
- "A list of URLs to render in the post."
- mediaUrls: [String]
-}
-```
-
-Input types can also be used when different operations require the exact same information, though we urge caution on over-using this technique since changes to `input` types are breaking changes for all operations which utilize them.
-
-Additionally, while it is possible to reuse an `input` type between a query and mutation which target the same resource, it's often best to avoid this since in many cases certain null fields might be tolerated for one but not the other.
-
-
Schema versioning
-
-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.
-
-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.
-
-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.
-
-
Understanding field usage
-
-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 what data is currently being used.
-
-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.
-
-> For details on how tracing data can be used to avoid shipping breaking changes to clients, check out the [schema history](https://www.apollographql.com/docs/engine/schema-history.html) tooling in [Apollo Engine](https://www.apollographql.com/engine) which utilizes actual usage data to provide warnings and notices about changes that might break existing clients.
-
-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.
-
-_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.
-
-We'll go over these two kinds of field rollovers separately and show how to make these changes safely.
-
-
Renaming or removing a field
-
-When a field is unused, renaming or removing it is as straightforward as it sounds: it can be renamed or removed. Unfortunately, if a GraphQL deployment doesn't have per-field usage metrics, additional considerations should be made.
-
-Take the following `user` query as an example:
-
-```graphql
-type Query {
- user(id: ID!): User
-}
-```
-
-We may want to rename it to `getUser` to be more descriptive of what the query is for, like so:
-
-```graphql
-type Query {
- getUser(id: ID!): User
-}
-```
-
-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.
-
-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:
-
-```js
-const getUserResolver = (root, args, context) => {
- context.User.getById(args.id);
-};
-
-const resolvers = {
- Query: {
- getUser: getUserResolver,
- user: getUserResolver,
- },
-};
-```
-
-
Deprecating a field
-
-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):
-
-```
-type Query {
- user(id: ID!): User @deprecated(reason: "renamed to 'getUser'")
- getUser(id: ID!): User
-}
-```
-
-GraphQL-aware client tooling, like GraphQL Playground and GraphiQL, use this information to assist developers in making the right choices. These tools will:
-
-* Provide developers with the helpful deprecation message referring them to the new name.
-* Avoid auto-completing the field.
-
-Over time, usage will fall for the deprecated field and grow for the new field.
-
-> Using tools like [Apollo Engine](https://www.apollographql.com/engine), it’s possible to make educated decisions about when to retire a field based on actual usage data through [schema analytics](https://www.apollographql.com/docs/engine/schema-analytics.html).
-
-
Non-breaking changes
-
-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:
-
-```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 [Apollo Engine](https://www.apollographql.com/engine), 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!
\ No newline at end of file
diff --git a/docs/source/platform/schema-registry.md b/docs/source/platform/schema-registry.md
index 1dd0a91..cebd542 100644
--- a/docs/source/platform/schema-registry.md
+++ b/docs/source/platform/schema-registry.md
@@ -70,7 +70,7 @@ The only change in this push is the addition of the `--tag` flag on the end of t
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 `APOLLO_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.
+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:
```js
diff --git a/docs/source/platform/schema-validation.md b/docs/source/platform/schema-validation.md
index 4a9ced6..b2b799f 100644
--- a/docs/source/platform/schema-validation.md
+++ b/docs/source/platform/schema-validation.md
@@ -1,5 +1,5 @@
---
-title: Schema validation and CI
+title: Validating schema changes
description: How to validate your schema in your existing CI workflow
---
@@ -9,6 +9,126 @@ A GraphQL schema can change in a number of ways between releases and, depending
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.
+
+
Understanding schema changes
+
+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.
+
+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.
+
+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.
+
+
Field usage
+
+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 what data is currently being used.
+
+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.
+
+> 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.
+
+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.
+
+_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.
+
+We'll go over these two kinds of field rollovers separately and show how to make these changes safely.
+
+
Renaming or removing a field
+
+When a field is unused, renaming or removing it is as straightforward as it sounds: it can be renamed or removed. Unfortunately, if a GraphQL deployment doesn't have per-field usage metrics, additional considerations should be made.
+
+Take the following `user` query as an example:
+
+```graphql
+type Query {
+ user(id: ID!): User
+}
+```
+
+We may want to rename it to `getUser` to be more descriptive of what the query is for, like so:
+
+```graphql
+type Query {
+ getUser(id: ID!): User
+}
+```
+
+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.
+
+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:
+
+```js
+const getUserResolver = (root, args, context) => {
+ context.User.getById(args.id);
+};
+
+const resolvers = {
+ Query: {
+ getUser: getUserResolver,
+ user: getUserResolver,
+ },
+};
+```
+
+
Deprecating a field
+
+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):
+
+```
+type Query {
+ user(id: ID!): User @deprecated(reason: "renamed to 'getUser'")
+ getUser(id: ID!): User
+}
+```
+
+GraphQL-aware client tooling, like GraphQL Playground and GraphiQL, use this information to assist developers in making the right choices. These tools will:
+
+* Provide developers with the helpful deprecation message referring them to the new name.
+* Avoid auto-completing the field.
+
+Over time, usage will fall for the deprecated field and grow for the new field.
+
+> 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.
+
+
Non-breaking changes
+
+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:
+
+```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:
@@ -80,6 +200,6 @@ jobs:
# of the schema to Apollo Engine.
- run: |
if [ "${CIRCLE_BRANCH}" == "master" ]; then
- apollo schema:publish
+ apollo service:push
fi
```
diff --git a/docs/source/references/apollo-engine.md b/docs/source/references/apollo-engine.md
new file mode 100644
index 0000000..622d041
--- /dev/null
+++ b/docs/source/references/apollo-engine.md
@@ -0,0 +1,194 @@
+---
+title: Apollo Engine guide
+description: Account management, data privacy, GDPR compliance, and other information about Apollo Engine
+---
+
+[Apollo Engine](https://engine.apollographql.com/) is our cloud service for schema management and performance metrics monitoring. Its foundation is built on two types of data input from servers: publishing schema introspections and sending traces of request execution. From those two data inputs we can provide rich schema usage insights, schema history management, schema change valiation, query usage insights, and more.
+
+Engine's core schema management features are all availble in an unlimited capacity for free, and always will be. Engine's advanced features, like resolver-level query tracing, longer data retention, and third-party integrations are available with subscriptions to the Apollo Team plan.
+
+More information on pricing and billing can be found [here](https://www.apollographql.com/plans/).
+
+
+
Accounts
+
+Engine accounts are authenticated using GitHub by default. There is also an SSO login option for teams that can be requested by [contacting us](https://www.apollographql.com/contact-sales/).
+
+
Team collaboration
+
+Engine accounts mirror your GitHub organizations. The first time you log in, we create a personal Engine account for you with the same name as your GitHub username.
+
+The Engine GitHub application asks for permission to read which GitHub organizations you’re in and their members and teams (but not code!). If you grant Engine permission to see an organization, we create an Engine account with the same name as that GitHub organization. All members of that organization on GitHub will be able to see the new account in Engine. This is how you create a shared team account in Engine.
+
+When you sign in to Engine, you will have access to all the teams where you're a member of the organization on GitHub. You can use the organization account picker to switch between accounts. If another member of a GitHub organization you belong to has already signed up the GitHub organization for Engine access, you’ll have access to that existing account.
+
+If you’d like to work with additional team members and you are the admin of a GitHub organization, simply add them to your GitHub organization. If you aren’t an admin, have an admin add you to their GitHub organization.
+
+
Adding an organization
+
+If you’re looking for a GitHub organization that you’re a member of and don’t see it in Engine, it’s likely that Engine does not have read access for that organization.
+
+If you want to add or remove an organization from Engine, you should manage those settings on GitHub. There, you will be able to Grant or Revoke access to Engine for organizations you can administer. For organizations you do not administer, you can Request access to Engine and the administrators will receive a request by E-mail.
+
+
GitHub permissions
+
+GitHub’s OAuth service is used for read-only information about organizations and users. Engine does not need access rights to your source code or to any other sensitive data in its login system.
+
+If your Engine account is owned by a GitHub organization, then Engine will allow all members of that organization to access the account. As you add or remove team members from your Github org, Engine will know about that and accordingly update the authorization for those users.
+
+
Support for non-GitHub login
+
+Engine was built to mirror GitHub’s login and does not currently support other forms of login or team creation. Our current recommendation for teams who want to use Engine but do not use GitHub is:
+
+1. Create a free GitHub organization (empty, public).
+2. Add your desired team members to the organization.
+3. Hide membership of the organization if desired.
+4. Use this organization to collaborate on Engine.
+
+
+
Services
+
+A service in Engine represents a "project" or "application". When you create a new service, we provision an API key for you that you can use to send performance metrics and schema versions to our cloud service. This information is then accessible to you through the Engine interface.
+
+
Creating a service
+
+To create a service, you will need to select an account for that service to belong to. All members of the account will be able to see the service’s data and settings options. You can transfer services between any Engine account that you’re a member of. To transfer a service, visit its Settings page and change the “Endpoint owner” to whichever account you’d like.
+
+Services in Engine have globally unique IDs, so we recommend that you prefix your service ID with the name of your company or organization.
+
+
Managing environments
+
+Each service in Engine should represent a single application, and environments within your application should be tracked using [schema tags](https://www.apollographql.com/docs/platform/schema-registry.html#schema-tags). All metrics that your server reports to Engine and all schema versions that you register should be tagged with their environment, and you'll be able to filter and look at the data for individual environments within the service.
+
+#### API keys
+
+API keys can be added and removed from a service at any time. They are used to both send data to Engine (eg. server reporting configuration) and fetch information from Engine (eg. vs code extension configuration).
+
+You can manage your API keys on your service's settings page. It's recommended that you use one API key per function (eg. one key per data source) to have more granular control over how your Engine data is sent and accessed.
+
+
Data privacy
+
+All data that is sent to Engine from your server can be configured and turned off to meet your PII/data privacy needs. This section will walk through what information Engine sees about your GraphQL service’s request, what Engine’s default behavior to handle request data is, and how you can configure Engine to the level of data privacy your team needs.
+
+
Architecture
+
+Engine is primarily a cloud service that ingests and stores performance metrics data from your server. There are two ways to get data into Engine:
+
+1. Use **Apollo Server 2** (Node servers) and configure performance metrics reporting by providing an Engine API key in your serer configuration.
+2. Run the **Engine proxy** (deprecated) in front of your server and install an Apollo tracing package in your server.
+
+#### Apollo Server 2
+
+If you’ve set up Engine metrics forwarding using Apollo Server 2, Apollo Server will automatically start tracing the execution your requests and forwarding that information to the Engine service. Engine uses this trace data to reconstruct both operation-level timing data for given query shapes and field-level timing data for your overall schema. This data will become available for you to explore in the Engine interface.
+
+Apollo Server will never forward the responses of your requests to Engine, but it will forward the shape of your request, the time it took each resolver to execute for that request, and the variables and headers of the request (configurable, see below).
+
+#### Engine Proxy (deprecated)
+
+This configuration option is primarily used to forward metrics to the Engine ingress from non-Node servers. The proxy is installed and run in your own environment on-prem as a separately hosted process that you route your client requests through. Apollo Server 1 users and other Node users users also have the option to run the Engine proxy as a sidecar next to their Node server.
+
+As your clients make requests to your server, the proxy reads response extension data to make caching decisions and aggregates tracing and error information into reports that it sends to the Engine ingress.
+
+While the Engine proxy sees your client request data and service response data, it only collects and forwards data that goes into the reports you see in the Engine dashboards. All information that is sent from your on-premise proxy to the out-of-band Engine cloud service is configurable and can be turned off through configuration options. Data is aggregated and sent approximately every 5 seconds.
+
+
Data collection
+
+This section describes which parts of your GraphQL HTTP requests are seen and collected by Engine.
+
+#### Query operation string
+
+Both Apollo Server 2 and the Engine proxy report the full operation string of your request to the Engine cloud service. Because of this, you should be careful to put any sensitive data like passwords and PII in the GraphQL variables object rather than in the operation string itself.
+
+#### Variables
+
+Both Apollo Server 2 and the Engine proxy will report your the query variables for each request to the Engine cloud service by default. This can be disabled in the following ways:
+
+- **Apollo Server 2** – use the privateVariables option in your Apollo Server configuration for Engine.
+- **Engine proxy** – use the privateVariables option in your proxy configuration, or prevent all variables from being reported with noTraceVariables option.
+
+#### Authorization & Cookie HTTP Headers
+
+Engine will **never** collect your application's `Authorization`, `Cookie`, or `Set-Cookie` headers and ignores these if received. Engine will collect all other headers from your request to show in the trace inspector, unless turned off with these configurations:
+
+- **Apollo Server 2** – use the [`privateHeaders` option](https://www.apollographql.com/docs/apollo-server/api/apollo-server.html#EngineReportingOptions) in your Apollo Server configuration for Engine.
+- **Engine Proxy** – use the [`privateHeaders` option](./proxy-config.html#Reporting) in your proxy configuration.
+
+If you perform authorization in another header (like `X-My-API-Key`), be sure to add this to `privateHeaders` configuration. Note that unlike headers in general, this configuration option **is** case-sensitive.
+
+
Response
+
+Let’s walk through Engine’s default behavior for reporting on fields in a typical GraphQL response:
+
+```
+// GraphQL Response
+{
+ "data": { ... }, // Never sent to the Engine cloud service
+ "errors": [ ... ], // Sent to Engine, used to report on errors for operations and fields.
+ "extensions": {
+ "tracing": { ... }, // Sent to Engine, used to report on performance data for operations and fields.
+ "cacheControl": { ... } // Sent to Engine, used to determine cache policies and forward CDN cache headers.
+ }
+}
+```
+
+#### `response.data`
+
+Neither Apollo Server 2 nor the Engine proxy will ever send the contents of this to the Engine cloud service. The responses from your GraphQL service stay on-prem.
+
+If you've configured whole query caching through the Engine proxy and Engine determines that a response it sees is cacheable, then the response will be stored in your [Engine cache](./caching.html#config.stores) (either in-memory in your proxy or as an external memcached you configure).
+
+#### `response.errors`
+
+If either Apollo Server 2 or the Engine proxy sees a response with an `"errors"` field, they will read the `message` and `locations` fields if they exist and report them to the Engine cloud service.
+
+You can disable reporting errors to the out-of-band Engine cloud service like so:
+
+- **Apollo Server 2** – enable the [`maskErrorDetails` option](/docs/apollo-server/api/apollo-server#EngineReportingOptions) to remove the messages and other details from error traces sent to Apollo's cloud service.
+- **Engine proxy** – use the [`noTraceErrors` option](./proxy-config.html#Reporting) to disable sending error traces to the Engine cloud service.
+
+#### Disable Reporting (Engine proxy)
+
+We've added the option to disable reporting of proxy stats and response traces to the Engine cloud service so that integration tests can run without polluting production data.
+
+To disable all reporting, use the [`disabled` option](./proxy-config.html#Reporting) for the Engine proxy.
+
+
GDPR
+
+Effective May 25, 2018, the General Data Protection Regulation (GDPR) expands European Union (EU) residents’ (Data Subjects) rights concerning their personal data. Meteor Development Group Inc. (“MDG” also dba Apollo) stands ready to assist our customers to become or remain compliant with GDPR after this crucial transition.
+
+#### What is GDPR?
+
+GDPR standardizes EU regulations and expands the rights of Data Subjects pertaining to personal data while expanding the definition of what constitutes personal data. GDPR provides Data Subjects with increased rights to control and delete their personal data, and it broadly prohibits the processing of special categories of personal data.
+
+#### How has Apollo prepared for GDPR?
+
+We have been complying with GDPR since before it became enforceable on May 25, 2018. We are enhancing our products, processes, and procedures to meet our obligations as a data processor (Processor).
+
+#### How will GDPR affect the way companies use Apollo's products or services?
+
+Our products and services are not intended to be used for processing personal data. Our products and services are focused on software, systems, and applications - not individuals. If a customer wishes to set up a custom API, custom attribute, or custom event to track such data, it may do so. Our processing is data agnostic and automated, so all data is processed in the same way in accordance with a customer’s configuration. If, however, a customer believes that it has included personal data in the information processed by Apollo, we will assist the customer in meeting its obligations in accordance with the requirements of GDPR and the terms of our Data Processing Agreement.
+
+#### How can Apollo assist customers in meeting their obligations under GDPR?
+
+As a Processor, we will assist customers in fulfilling their obligations as data controllers (Controllers) by:
+
+- supporting customers in complying with requests from Data Subjects
+- aggregating applicable personal data for customers replying to complaints from Data Subjects
+- replying to investigations and inquiries from supervisory authorities concerning processing activities on behalf of a customer
+- conducting Data Protection Impact Assessments
+
+#### How can Apollo help address requests from Data Subjects?
+
+Apollo has implemented a process to intake, review, and fulfill customer requests arising from Data Subject Access Requests (DSAR) they receive. As a result of a DSAR, customers might request that Apollo securely delete or return the Data Subject’s personal data. Due to their sensitivity, such requests will be handled by Apollo on a case-by-case basis.
+
+#### Where can I learn more about Apollo's security and privacy policies?
+
+The legal terms and policies that apply to Apollo's corporate websites and customer products or services are available at https://www.meteor.com/policy.
+
+#### Where can I get more help?
+
+If you have any questions (including interest in a Data Processing Addendum (DPA)), or encounter any issues, please reach out to support.
+
+
Policies and Agreements
+
+To learn about other ways that we protect your data, please read over our [Terms of Service](https://www.apollographql.com/policies/terms) and [Privacy Policy](https://www.apollographql.com/policies/privacy).
diff --git a/docs/source/resources/faq.md b/docs/source/resources/faq.md
index 5ab864a..dbcc171 100644
--- a/docs/source/resources/faq.md
+++ b/docs/source/resources/faq.md
@@ -3,7 +3,7 @@ title: Frequently Asked Questions
description: Common questions asked at each stage of GraphQL adoption
---
-Everyone has questions about how to properly set up a GraphQL schema, but not all questions are alike. In different stages of development, different things matter. This guide will questions that people commonly have have at every step along the journey to GraphQL in production.
+Everyone has questions about how to properly set up a GraphQL schema, but not all questions are alike. In different stages of development, different things matter. This guide answers questions that people commonly have at every step along the journey to GraphQL in production.
## Learning GraphQL
@@ -66,7 +66,7 @@ Schemas should be designed with the needs of the client in mind. Rather than mod
As with any service, it's important to track errors and their causes. There are many kinds of errors that can occur with a GraphQL Schema. Some of these include service errors, where the schema can't access underlying services, and user errors, where a user enters invalid information in a query or mutation.
-GraphQL is resilient to some of these errors. Since the schema is strongly typed, the designer has the ability to restrict what type of data users can enter and what type the resolvers can return. This type system catches many errors, and requires no manual checks.
+GraphQL is resilient to some of these errors. Since the schema is strongly typed, the designer has the ability to restrict what type of data users can enter and what type the resolvers can return. This type system catches many errors and requires no manual checks.
For errors not prevented by the type system, it's helpful to know what exact queries were made, and with what variables. [Apollo Engine](https://www.apollographql.com/engine) is a tool that does exactly this. It can help discover and reproduce errors by showing the exact conditions in which the error occurred.
@@ -90,15 +90,15 @@ Authentication and authorization are important topics to discuss with any API. G
Public APIs of any kind need some kind of safeguards against malicious queries. Since GraphQL allows for recursive queries, it wouldn't be hard to create a query that is overly complicated and acts as a DoS attack, even by accident. There are multiple ways to prevent something like this from happening, from complexity limiting to query depth limiting. Read the [guide on security](../guides/security.html) to learn more.
-#### What kinds of cache should I setup?
+#### What kinds of cache should I set up?
GraphQL can be cached in multiple places.
On the client, caches can prevent multiple queries from being called when not necessary. Client caches for GraphQL differ from REST clients in one important way: cache can handle queries that have never been made. This is possible because of how a GraphQL response is normalized and stored. For example, if a client requests a list of movies, each movie is cached separately on the client. Later, if the client requests a single movie in a different query and the needed information is in the cache, the request doesn't have to be made. This normalized cache is a part of `apollo-client` by default.
-Cache can also be setup at the schema level. Whole-query caching, partial-query caching, and cache backed by a CDN can all be used to lower response times, and make a GraphQL schema as performant as possible.
+Cache can also be set up at the schema level. Whole-query caching, partial-query caching, and cache backed by a CDN can all be used to lower response times and make a GraphQL schema as performant as possible.
-Whole-query and CDN caches are most useful when an API receives many of the same queries. This commonly happens with public data, like content on pages of a site. Regardless of whether the API is used for public data or not, these caches almost always provide large performance benefits, and are highly recommended. You can read more about how to set up whole-query and CDN caching with `apollo-server` 2.0 [here](https://www.apollographql.com/docs/guides/performance.html).
+Whole-query and CDN caches are most useful when an API receives many of the same queries. This commonly happens with public data, like content on pages of a site. Regardless of whether the API is used for public data or not, these caches almost always provide large performance benefits and are highly recommended. You can read more about how to set up whole-query and CDN caching with `apollo-server` 2.0 [here](https://www.apollographql.com/docs/guides/performance.html).
Partial query caching can be achieved by caching the responses from underlying services with something like Redis or Memcache. With this strategy, even if two queries look completely different from one another, if there is any duplication of data fetched, those results can be shared, preventing unnecessary traffic. The [`RESTDataSource`](https://www.apollographql.com/docs/apollo-server/features/data-sources.html) does this automatically if the appropriate `cache-control` headers are present in REST responses.
@@ -108,7 +108,7 @@ Many apps and sites are powered almost completely by an API such as a GraphQL sc
[Apollo Engine](https://www.apollographql.com/engine) is a great tool to track many of these things. It allows close inspection of fields to make it easy to see both total response times as well as how long each field took to execute.
-Engine also has some integrations to make monitoring easier. The [Slack Integration](https://www.apollographql.com/docs/engine/integrations/slack.html#setup) delivers daily reports to give teams a quick overview of the health of their schema. The [DataDog integration](https://www.apollographql.com/docs/engine/integrations/datadog.html#Monitoring-with-Datadog) works with existing DataDog accounts, to help teams track schema performance. When things go wrong, Engine has [configurable alerts](https://www.apollographql.com/docs/engine/features/alerts.html) to notify teams of issues through PagerDuty or Slack.
+Apollo Engine also has some integrations to make monitoring easier. The [Slack Integration](https://www.apollographql.com/docs/engine/integrations/slack.html#setup) delivers daily reports to give teams a quick overview of the health of their schema. The [DataDog integration](https://www.apollographql.com/docs/engine/integrations/datadog.html#Monitoring-with-Datadog) works with existing DataDog accounts, to help teams track schema performance. When things go wrong, Engine has [configurable alerts](https://www.apollographql.com/docs/engine/features/alerts.html) to notify teams of issues through PagerDuty or Slack.
## Moving a product to GraphQL
diff --git a/docs/source/resources/graphql-glossary.md b/docs/source/resources/graphql-glossary.md
index c29ba8a..d27a118 100644
--- a/docs/source/resources/graphql-glossary.md
+++ b/docs/source/resources/graphql-glossary.md
@@ -351,6 +351,32 @@ subscription onCommentAdded($repoFullName: String!){
Type System
A collection of types which characterizes the set of data that can be validated, queried and executed on a GraphQL API.
+
Variable
+
+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){
+ firstName
+ }
+}
+```
+
+In the query above, `userId` is a variable. The variable and its type is declared in the operation signature, signified by a `$`. The type of the variable here is a required `ID`. It's important to note that variable types must match the type of the arguments that they fill.
+
+The userId variable would be passed to the operation by `apollo-client` like this:
+
+```js
+client.query({ query: getUserQuery, variables: { userId: 1 }});
+```
+
+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/production.md b/docs/source/tutorial/production.md
index 6893822..9626291 100644
--- a/docs/source/tutorial/production.md
+++ b/docs/source/tutorial/production.md
@@ -30,7 +30,7 @@ Our key is now stored under the environment variable `ENGINE_API_KEY`.
It's time to publish our schema to Engine! First, start your server in one terminal window by running `npm start`. In another terminal window, run:
```bash
-npx apollo schema:check && npx apollo schema:publish
+npx apollo service:check && npx apollo service:push
```
> npx is a tool bundled with npm for easily running packages that are not installed globally.
@@ -60,4 +60,4 @@ $ npx now
The `now` command immediately deploys our graph API to the cloud and returns the hosted URL. Make sure you either copy the URL or run `npx now ls` in your terminal to retrieve the URL, since we'll need it in the following section when we build our client.
-Congrats on deploying your first Apollo graph API! 🚀 Let's move on to the second half of the tutorial where we connect the API we just built to a React app.
\ No newline at end of file
+Congrats on deploying your first Apollo graph API! 🚀 Let's move on to the second half of the tutorial where we connect the API we just built to a React app.
diff --git a/docs/source/tutorial/resolvers.md b/docs/source/tutorial/resolvers.md
index 40e6d3a..3d69588 100644
--- a/docs/source/tutorial/resolvers.md
+++ b/docs/source/tutorial/resolvers.md
@@ -15,7 +15,7 @@ Before we can start writing resolvers, we need to learn more about what a resolv
fieldName: (parent, args, context, info) => data
```
-* **root**: An object that contains the result returned from the resolver on the parent type
+* **parent**: An object that contains the result returned from the resolver on the parent type
* **args**: An object that contains the arguments passed to the field
* **context**: An object shared by all resolvers in a GraphQL operation. We use the context to contain per-request state such as authentication information and access our data sources.
* **info**: Information about the execution state of the operation which should only be used in advanced cases