From b53ed6b3434996ef9315f15473e5d68dab1abd72 Mon Sep 17 00:00:00 2001 From: Trevor Blades Date: Fri, 26 Apr 2019 15:20:18 -0700 Subject: [PATCH] Clean up markdown for use with gatsby-remark system --- docs/source/intro/benefits.md | 22 ++-- docs/source/intro/platform.md | 12 +- docs/source/old/performance.md | 18 +-- docs/source/platform/client-awareness.md | 14 +-- docs/source/platform/editor-plugins.md | 34 +++--- docs/source/platform/integrations.md | 18 +-- docs/source/platform/operation-registry.md | 18 +-- docs/source/platform/schema-registry.md | 26 ++--- docs/source/platform/schema-validation.md | 16 +-- docs/source/references/apollo-config.md | 42 +++---- docs/source/references/apollo-engine.md | 36 +++--- .../references/engine-proxy-1.0-migration.md | 9 +- docs/source/references/engine-proxy.md | 90 ++++++--------- docs/source/references/setup-analytics.md | 22 ++-- docs/source/resources/graphql-glossary.md | 107 +++++++++--------- docs/source/tutorial/client.md | 25 ++-- docs/source/tutorial/data-source.md | 12 +- docs/source/tutorial/introduction.md | 14 +-- docs/source/tutorial/local-state.md | 30 ++--- docs/source/tutorial/mutations.md | 18 +-- docs/source/tutorial/production.md | 10 +- docs/source/tutorial/queries.md | 36 +++--- docs/source/tutorial/resolvers.md | 31 +++-- docs/source/tutorial/schema.md | 14 +-- 24 files changed, 324 insertions(+), 350 deletions(-) diff --git a/docs/source/intro/benefits.md b/docs/source/intro/benefits.md index 028d7e7..7f00304 100644 --- a/docs/source/intro/benefits.md +++ b/docs/source/intro/benefits.md @@ -7,15 +7,15 @@ Managing data in modern applications can present a number of challenges. Develop Adopting GraphQL in your organization will ease these pain points considerably. Read on to learn how GraphQL's declarative approach to data fetching will simplify data transformation and speed up your API. You'll also learn how the Apollo platform enables faster development cycles thanks to its advanced ecosystem of tooling and excellent developer experience. -

Developer experience

+## Developer experience Implementing GraphQL in your organization via the Apollo platform can help you ship features faster due to its excellent developer experience. Our #1 goal is to simplify data management across the stack. Features that are normally difficult to execute, such as fullstack caching, data normalization, and optimistic UI suddenly become trivial thanks to Apollo Client, Apollo Server, and Apollo Engine. Let's learn how! -

Explore your API

+### Explore your API GraphQL's strongly typed query language enables developers to take advantage of incredible tooling for exploring GraphQL APIs. Thanks to GraphQL's introspection system, developers can query a GraphQL schema for information about what queries and types it supports. Introspection unlocks some really cool features, such as automatic documentation, autocomplete, and more. -

GraphQL Playground

+#### GraphQL Playground [GraphQL Playground](https://github.com/prismagraphql/graphql-playground) by Prisma is an excellent IDE featuring automatically generated docs for your schema and query execution with autocomplete. At a glance, you can see all the data available in your GraphQL API without diving into the backend code or knowing what source it came from. @@ -23,13 +23,13 @@ GraphQL's strongly typed query language enables developers to take advantage of Apollo Server 2+ sets up GraphQL Playground out of the box, so you can start exploring your schema and executing queries immediately. -

Apollo DevTools

+#### Apollo DevTools Apollo DevTools is a Chrome extension that allows you to inspect your Apollo Client cache, track active queries, and view mutations. You also have access to GraphiQL within Apollo DevTools which is convenient for testing queries as you're working on front-end code with Apollo Client. ![Apollo DevTools](../assets/dev-tools.png) -

Simplify front-end code

+### Simplify front-end code If you've worked with REST and a state management library like Redux, you're probably used to writing action creators, reducers, normalizing your data, and integrating middleware to make a single network request. With Apollo Client, you no longer have to worry about any of these concerns! Apollo Client sets up everything you need for a production-ready app so you can focus on writing queries instead of thousands of lines of state management code. @@ -43,7 +43,7 @@ const client = new ApolloClient({ Teams who have switched to Apollo Client have reported [deleting thousands of lines of state management code](https://blog.apollographql.com/reducing-our-redux-code-with-react-apollo-5091b9de9c2a) and lots of complexity from their application. Since Apollo Client supports managing both local and remote data, you can use the Apollo cache as a single source of truth for all global state in your application. -

Modern tooling

+### Modern tooling Developing your GraphQL API with the Apollo platform gives teams access to modern tooling that helps them uncover bugs quickly, gain visibility into their API, and develop challenging features such as caching with confidence. @@ -51,7 +51,7 @@ Developing your GraphQL API with the Apollo platform gives teams access to moder ![Apollo Engine](../assets/engine.png) -

Declarative data fetching

+## Declarative data fetching One of the main advantages of adopting GraphQL is its declarative approach to data fetching. With GraphQL, there's no need to call multiple endpoints from the client or aggregate the data manually like you have to with traditional REST data fetching. Instead, you specify exactly the data you need and GraphQL gives you exactly what you asked for. @@ -103,11 +103,11 @@ Apollo Client takes care of the request cycle from start to finish, including tr You’ll find that when you switch to Apollo Client, you’ll be able to delete a lot of unnecessary code related to data management. The exact amount will vary depending on your application, but some teams have reported up to thousands of lines. To learn more about how Apollo Client enables advanced features like optimistic UI, refetching, and pagination with less code, check out our [documentation for Apollo Client](/docs/react/). -

Improved performance

+## Improved performance In many cases, layering a GraphQL API over your existing REST endpoints can improve your app's performance, especially on devices with slow network connections. While you should always measure to determine how integrating GraphQL will affect your application, it's generally accepted that GraphQL improves performance by helping avoid round trips to the server and reducing payload size. -

Smaller payloads

+### Smaller payloads Since the response back from the server contains only the properties you specify in your query, GraphQL can significantly reduce payload size compared to a REST endpoint. Let's take a look at our dogs query from earlier in the article: @@ -130,7 +130,7 @@ const GET_DOGS = gql` The response back from the server will be a list of dog objects with `id`, `breed`, `image`, and `activities` properties. It doesn't matter if the underlying REST endpoints we call in our resolvers return back objects with 100 properties! All of those extraneous properties will be filtered out before the response is sent back to the client. -

Avoid round trips

+### Avoid round trips Since each GraphQL request returns only one response, switching to GraphQL can help you avoid costly round trips from the client to your server. With REST, each resource represents a round trip, which can quickly add up. If you're fetching items in a list, you'll have to complete a round trip for every resource multiplied by the number of items, causing slow load times, especially on mobile devices. @@ -142,7 +142,7 @@ GET /api/dogs/activities With GraphQL, each query represents a single round trip from the client to server. If you'd like to reduce round trips even further, you can implement [query batching](/docs/react/advanced/network-layer#query-batching) to batch multiple queries into a single request. -

Ready for production

+### Ready for production While the GraphQL specification was first made public by Facebook in 2015, GraphQL has been a key component of their mobile application deployment since 2012. diff --git a/docs/source/intro/platform.md b/docs/source/intro/platform.md index 41c1b5b..b106998 100644 --- a/docs/source/intro/platform.md +++ b/docs/source/intro/platform.md @@ -18,7 +18,7 @@ are: Graph layer -

Core open source components

+## Core open source components - **Apollo Server** is a JavaScript GraphQL server for defining a _schema_ and a set of _resolvers_ that implement each part of that @@ -45,7 +45,7 @@ are: - **Apollo CLI** is a simple command line client that provides access to Apollo cloud services. -

Cloud services

+## Cloud services - **Schema registry** — a registry for GraphQL schemas that acts as a central source of truth for a schema, enriched with additional @@ -66,18 +66,18 @@ are: and important metadata such as client identity and which version of the schema was queried. -

Gateway

+## Gateway - **Apollo Gateway** — a configuration of Apollo Server and additional plugins that functions as a GraphQL gateway. The gateway composes separately deployed "micro-schemas" that reference each other into a single master schema, which looks to a client just like any regular GraphQL schema. To answer queries, the gateway builds a query plan, fetches data from each upstream GraphQL service, and assembles it all back together into a single result. -

Workflows

+## Workflows On top of these components, Apollo implements some useful workflows for managing a GraphQL API. Each of these workflows makes use of several different parts of the platform, working together. Some examples are: -

Schema change validation

+### Schema change validation Apollo includes a facility for checking the compatibility of a given schema against a set of previously-observed operations. This uses the @@ -88,7 +88,7 @@ cause an incompatibility error. The compatibility check runs statically, taking advantage of the schema's type definitions, so it doesn't require a running server. -

Safelisting

+### Safelisting Apollo provides an end-to-end mechanism for _safelisting_ known clients and queries, a recommended best practice that limits production use of a diff --git a/docs/source/old/performance.md b/docs/source/old/performance.md index 0bacb5f..67e1d73 100644 --- a/docs/source/old/performance.md +++ b/docs/source/old/performance.md @@ -7,13 +7,13 @@ A common challenge that developers experience as they build products is how quic This guide details some practices around enhancing network performance which will help bring data closer to your clients. -

Automatic Persisted Queries

+## Automatic Persisted Queries The size of individual GraphQL query strings can be a major pain point. Apollo Server implements Automatic Persisted Queries (APQ), a technique that greatly improves network performance for GraphQL with zero build-time configuration. A persisted query is a ID or hash that can be sent to the server instead of the entire GraphQL query string. This smaller signature reduces bandwidth utilization and speeds up client loading times. Persisted queries are especially nice paired with GET requests, enabling the browser cache and [integration with a CDN](#get). With Apollo Persisted Queries, the ID is a deterministic hash of the input query, so we don't need a complex build step to share the ID between clients and servers. If a server doesn't know about a given hash, the client can expand the query for it; Apollo Server caches that mapping. -

Setup

+### Setup To get started with APQ, add the [Automatic Persisted Queries Link](https://github.com/apollographql/apollo-link-persisted-queries) to the client codebase with `npm install apollo-link-persisted-queries`. Next incorporate the APQ link with Apollo Client's link chain before the HTTP link: @@ -51,7 +51,7 @@ const server = new ApolloServer({ }); ``` -

Verify

+### Verify Apollo Server's persisted queries configuration can be tested from the command-line. The following examples assume Apollo Server is running at `localhost:4000/`. This example persists a dummy query of `{__typename}`, using its sha256 hash: `ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38`. @@ -81,11 +81,11 @@ curl -g 'http://localhost:4000/?extensions={"persistedQuery":{"version":1,"sha25 Expect a response of `{"data": {"__typename": "Query"}}"`, as the query string is loaded from the cache. -

Using GET requests with APQ to enable CDNs

+### Using GET requests with APQ to enable CDNs A great application for APQ is running Apollo Server behind a CDN. Many CDNs only cache GET requests, but many GraphQL queries are too long to fit comfortably in a cacheable GET request. When the APQ link is created with `createPersistedQueryLink({useGETForHashedQueries: true})`, Apollo Client automatically sends the short hashed queries as GET requests allowing a CDN to serve those request. For full-length queries and for all mutations, Apollo Client will continue to use POST requests. -

How it works

+### How it works The mechanism is based on a lightweight protocol extension between Apollo Client and Apollo Server. It works as follows: @@ -98,13 +98,13 @@ The mechanism is based on a lightweight protocol extension between Apollo Client New Query Path -

CDN Integration

+## CDN Integration Content Delivery Networks (CDNs) such as [fly.io](https://fly.io), [Cloudflare](https://www.cloudflare.com/), [Akamai](https://www.akamai.com/) or [Fastly](https://www.fastly.com/) allow content caching close to clients, delivering data with low latency from a nearby server. Apollo Server makes it straightforward to use CDNs with GraphQL queries to cache full responses while still executing more dynamic queries. To use Apollo Server behind a CDN, we define which GraphQL responses the CDN is allowed to cache. On the client, we set up [automatic persisted queries](#automatic-persisted-queried) to ensure that GraphQL requests are in a format that a CDN can understand. -

Step 1: Add cache hints to the GraphQL schema

+### Step 1: Add cache hints to the GraphQL schema Add cache hints as [directives](./directives.html) to GraphQL schema so that Apollo Server knows which fields and types are cacheable and for how long. For example, this schema indicates that all fields that return an `Author` should be cached for 60 seconds, and that the `posts` field should itself be cached for 180 seconds: @@ -130,7 +130,7 @@ const server = new ApolloServer({ After this step, Apollo Server will serve the HTTP `Cache-Control` header on fully cacheable responses, so that any CDN in front of Apollo Server will know which responses can be cached and for how long! A "fully cacheable" response contains only data with non-zero `maxAge`; the header will refer to the minimum `maxAge` value across the whole response, and it will be `public` unless some of the data is tagged `scope: PRIVATE`. To observe this header, use any browser's network tab in its dev tools. -

Step 2: Enable automatic persisted queries

+### Step 2: Enable automatic persisted queries Often, GraphQL requests are big POST requests and most CDNs will only cache GET requests. Additionally, GET requests generally work best when the URL has a bounded size. Enabling automatic persisted queries means that short hashes are sent over the wire instead of full queries, and Apollo Client can be configured to use GET requests for those hashed queries. @@ -164,7 +164,7 @@ Make sure to include `useGETForHashedQueries: true`. Note that the client will s If configured correctly, browser's dev tools should verify that queries are now sent as GET requests, and receive appropriate `Cache-Control` response headers. -

Step 3: Set up a CDN!

+### Step 3: Set up a CDN! How exactly this works depends on exactly which CDN you chose. Configure your CDN to send requests to Apollo Server. Some CDNs may need to be specially configured to honor origin Cache-Control headers; for example, here is [Akamai's documentation on that setting](https://learn.akamai.com/en-us/webhelp/ion/oca/GUID-57C31126-F745-4FFB-AA92-6A5AAC36A8DA.html). If all is well, cacheable queries should now be saved by the CDN! diff --git a/docs/source/platform/client-awareness.md b/docs/source/platform/client-awareness.md index 5bfdd2f..af580e1 100644 --- a/docs/source/platform/client-awareness.md +++ b/docs/source/platform/client-awareness.md @@ -19,7 +19,7 @@ Apollo Server 2.2.3+ will look for specific the request headers, `apollographql- With Apollo Client 2.4.6+, simply passing the `name` and `version` options in your `ApolloClient` constructor will automatically add these headers to every request. Setting up client identity reporting is as simple as adding configuration to Apollo Client: -```js line=8-9 +```js{8-9} import { ApolloClient } from 'apollo-client'; import { HttpLink } from 'apollo-link-http'; @@ -62,10 +62,10 @@ Similarly to deprecation, adding fields to your graph often means that clients w The requester is responsible for setting HTTP headers on its requests in a way the server will understand. As noted in "setup", Apollo Client and Server will handle this automatically. For advanced cases, rather than setting the `name` and `version` on `ApolloClient`, `headers` can be set on the `HttpLink` directly. -```js line=8-16 -import { ApolloClient } from 'apollo-client'; -import { HttpLink } from 'apollo-link-http'; -import { ApolloLink } from 'apollo-link'; +```js{8-16} +import { ApolloClient } from "apollo-client"; +import { HttpLink } from "apollo-link-http"; +import { ApolloLink } from "apollo-link"; const client = new ApolloClient({ link: new HttpLink({ @@ -85,8 +85,8 @@ to a request. To send client-tagged metrics to Apollo, pass a `generateClientInfo` function into the `ApolloServer` constructor. The following example checks the headers and provides a fallback: -```js line=8-22 -const { ApolloServer } = require('apollo-server'); +```js{8-22} +const { ApolloServer } = require("apollo-server"); const server = new ApolloServer({ typeDefs, diff --git a/docs/source/platform/editor-plugins.md b/docs/source/platform/editor-plugins.md index c65f3d8..7b71430 100644 --- a/docs/source/platform/editor-plugins.md +++ b/docs/source/platform/editor-plugins.md @@ -7,7 +7,7 @@ GraphQL has the potential to create incredible developer experiences, thanks to Using jump to definition on a fragment -

Apollo VS Code

+## Apollo VS Code The [VS Code extension](https://marketplace.visualstudio.com/items?itemName=apollographql.vscode-apollo) for Apollo brings an all-in-one tooling experience for developing apps with Apollo. @@ -20,14 +20,14 @@ The [VS Code extension](https://marketplace.visualstudio.com/items?itemName=apol - Manage [client-only](#client-only-schemas) schemas - [Switch schema tags](#commands) to work with schemas running on different environments -

Getting started

+## Getting started To get all of the benefits of the VS Code experience, it's best to link the schema that is being developed against **before** installing the extension. The best way to do that is by [publishing a schema](./schema-registry.html#publish) to the Apollo schema registry. Once that is done, two steps are needed: 1. Create an `apollo.config.js` at the root of the project 2. Copy an API key from the Engine dashboard of the published service -

Setting up an Apollo config

+### Setting up an Apollo config In order for the VS Code plugin to know how to find the schema, it needs to be linked to either a published schema or a local one. To link a project to a published schema, edit the `apollo.config.js` file to look like this: @@ -43,7 +43,9 @@ The `service` name here is the ID of the graph you've created in [Engine](https: > **Note:** The ID of your graph can be found in its URL in Engine. We use the ID so you can change your graph's name freely without having to update this. This will be easier to manage in the future. -

Setting up an API key

+### Setting up an API key + +To authenticate with Engine to pull down the schema, create a file next to the `apollo.config.js` called `.env`. This should be an untraced file (i.e. don't push it to GitHub). Go to the settings page of the published service and create a new API key. To authenticate with Engine to pull down the schema, create a file next to the `apollo.config.js` called `.env`. This should be an untraced file (i.e. don't push it to GitHub). Go to the settings page of your graph in Engine to get the API key. @@ -57,7 +59,7 @@ ENGINE_API_KEY= After this is done, VS Code can be reloaded and the Apollo integration will connect to Engine to provide autocomplete, validation, and more. -

Local schemas

+### Local schemas Sometimes it may make sense to link the editor to a locally running version of a schema to try out new designs that are in active development. To do this, the `apollo.config.js` file can be linked to a local service definition: @@ -74,7 +76,7 @@ module.exports = { Linking to the local schema won't provide all features such as switching schema tags and performance metrics. See [the Apollo config docs](https://www.apollographql.com/docs/references/apollo-config) for more details on configuration options. -

Client-only schemas

+### Client-only schemas One of the best features of the VS Code extension is the automatic merging of remote schemas and local ones when using integrated state management with Apollo Client. This happens automatically whenever schema definitions are found within a client project. By default, the VS Code extension will look for all files under `./src` to find both the operations and schema definitions for building a complete schema for the application. @@ -90,7 +92,7 @@ module.exports = { } ``` -

Get the extension

+### Get the extension Once you have a config set up and a schema published, [install the Apollo GraphQL extension](https://marketplace.visualstudio.com/items?itemName=apollographql.vscode-apollo), then try opening a file containing a GraphQL operation. @@ -98,29 +100,29 @@ When a file open, clicking the status bar icon will open the output window and p Clicking the status bar icon to open the output pane -

Features

+## Features Apollo for VS Code brings many helpful features for working on a GraphQL project. -

Intelligent autocomplete

+### Intelligent autocomplete Once configured, editors have full knowledge of the schema clients are running operations against, including client-only schemas (for things like local state mutations). Because of this, editors have the ability to autocomplete fields and arguments as you type. vscode completing a field when typing -

Inline errors and warnings

+### Inline errors and warnings Editors can use local or published schemas to validate operations before running them. **Syntax errors**, **invalid fields or arguments**, and even **deprecated fields** instantly appear as errors or warnings right in your editor, ensuring all developers are working with the most up-to-date production schemas. tooltip showing a field deprecation warning and error -

Inline field type information

+### Inline field type information Because of GraphQL's strongly-typed schema, editors not only know about which fields and arguments are valid, but also what types are expected. Hover over any type in a valid GraphQL operation to see what type that field returns and whether or not it can be null. a tooltip showing a Boolean type for a field -

Performance insights

+### Performance insights GraphQL's flexibility can make it difficult to predict the cost of an operation. Without insight into how expensive an operation is, developers can accidentally write queries that place strain on their graph API's underlying backends. Thanks to the Apollo platform's integration with VS Code and our trace warehouse, teams can avoid these performance issues altogether by instantly seeing the cost of a query right in their editor. @@ -130,21 +132,21 @@ The VS Code extension will show inline performance diagnostics when connected to Performance annotation next to a field -

Syntax highlighting

+### Syntax highlighting Apollo's editor extension provides syntax highlighting for all things GraphQL, including schema definitions in `.graphql` files, complex queries in TypeScript, and even client-only schema extensions. Syntax highlighting for GraphQL works out-of-the-box for `.graphql`, `.gql`, `.js` and `.ts` file types. - +### Navigating projects Navigating large codebases can be difficult, but the Apollo GraphQL extension makes this easier. Right-clicking on any field in operations or schemas gives you the ability to jump to (or peek at) definitions, as well as find any other references to that field in your project. Using jump to definition on a fragment -

Schema variant switching

+### Schema variant switching Apollo supports publishing multiple versions ([variants](http://localhost:8000/platform/schema-registry#schema-tags)) of a schema. This is useful for developing on a future development schema and preparing your clients to conform to that schema. To switch between schema variants, open the Command Palette (`cmd + shift + p` on mac), search "Apollo" and choose the "Apollo: Select Schema Tag" option. -

Troubleshooting

+## Troubleshooting The most common errors are configuration errors, like a missing `.env` file or incorrect service information in the `apollo.config.js` file. Please see [the Apollo config docs](https://www.apollographql.com/docs/references/apollo-config) for more configuration guidance. diff --git a/docs/source/platform/integrations.md b/docs/source/platform/integrations.md index 6bbf440..058d4b8 100644 --- a/docs/source/platform/integrations.md +++ b/docs/source/platform/integrations.md @@ -9,21 +9,21 @@ One of our fundamental beliefs is that our Apollo workflows should hook into and 1. [**Slack**](#slack) — Get a daily summary of key information from your server, including the overall request rate, error rate, and performance latency. Set up notifications for noteworthy events in your service, like increases in errors or particularly slow response times for important queries. 1. [**Datadog**](#datadog) — Forward the key metrics and performance data available from Engine to Datadog as well. -

GitHub

+## GitHub Building tools to help you safely collaborate on the evolution of your graph is one of our biggest focuses at Apollo. To make [schema change validation](/docs/platform/schema-validation.html) as easy to set up as possible, we've built an Apollo app for GitHub that provides status checks on pull requests when schema changes are proposed. ![GitHub Status View](../img/schema-validation/github-check.png) -

Install the GitHub application

+### Install the GitHub application Go to [https://github.com/apps/apollo-engine](https://github.com/apps/apollo-engine) and click the `Configure` button to install the Apollo Engine integration on the GitHub profile or organization that you want to set up checks for. -

Run validation on each commit

+### Run validation on each commit Next, make sure your CI has a step to run the schema validation command. This is accomplished by adding the `apollo schema:check` command directly as a step in your CI. For CircleCI it could look something like this: -```yaml line=13,29,33-36 +```yaml{13,29,33-36} version: 2 jobs: @@ -68,14 +68,14 @@ The `apollo schema:check` command checks for differences in your schema between Because you installed the Engine app on GitHub, the check you've added will show up as a line in your GitHub checks list. If there are changes in your schema you'll be able to review them by clicking the "Details" link. By enabling schema validation in your continuous integration workflow (eg. CircleCI, etc.), you're alerting developers of any potential problems directly in their pull requests, thereby giving them critical feedback where it's most useful. -

Slack

+## Slack Our Apollo Slack integration brings your server's performance metrics and analytics data from Apollo Engine directly to your team's Slack workspace so you can be notified of potential issues proactively. The integration does two main things: 1. Send a [**daily snapshot**](#slack-reports) of the request rate, error rate, and performance latency of your graph. 1. Send [**notifications**](#slack-notifications) that are triggered on thresholds like error percentage and performance latency. -

Configure the integration

+### Configure the integration The Apollo Slack integration is set up and configured through the Engine UI. If you do not yet have account, [**follow this guide**](/docs/apollo-server/features/metrics.html#Apollo-Engine) to get started connecting your server to Engine. @@ -89,7 +89,7 @@ Once you've configured your Slack channel you'll be able to turn on daily report ![The Integrations tab in Engine](../img/integrations/integrations-tab.png) -

Daily reports

+### Daily reports Daily reports from Engine are sent out around 9am in whichever timezone you configure them to be in. You turn them on in the "Integrations" tab as shown above. The reports have a set format that gives a birds-eye view of what your GraphQL API delivered in the previous day: @@ -103,7 +103,7 @@ We've constructed the report provided to give you an actionable summary of what' 2. **p95 service time:** This shows you how long queries are taking to execute. We selected p95 since it’s the best overall representation of how your users are experiencing your app. You can use this to identify that your API is overloaded and users are seeing long loading delays, or to find out which queries are taking the longest to run. This is usually directly connected to UI performance, so a 500ms query probably means some part of your UI is taking that long to display. 3. **Error percentage:** This will show you how many of your GraphQL requests end up with an error result. Spikes in errors might be the result of some underlying backend malfunctioning. You can also see which of your operations are most error-prone. -

Notifications

+### Notifications In Engine you can configure notifications that are triggered on the performance data of your graph, like error percentages and request latencies. This is particularly useful for detecting anomalies, especially around releases. Notifications can be configured to monitor the following metrics for either your entire GraphQL service or individual operations: @@ -117,7 +117,7 @@ The triggers you set up are evaluated on a rolling five minute window. For examp ![Slack Alert](../img/integrations/slack-notification.png) -

Datadog

+## Datadog The Apollo Datadog integration allows you to forward all the performance metrics and analytics data that's available to you in Engine to Datadog as well. This is particularly convenient for teams already relying on Datadog for their monitoring, and of the best perks is that Datadog has advanced filtering features that alerts can be set on, and teams can set those alerts based on their GraphQL metrics data from Engine through Datadog. diff --git a/docs/source/platform/operation-registry.md b/docs/source/platform/operation-registry.md index 33916b3..932c037 100644 --- a/docs/source/platform/operation-registry.md +++ b/docs/source/platform/operation-registry.md @@ -125,7 +125,7 @@ In the future, the subscription support will have its request pipeline unified w To disable subscriptions support on Apollo Server 2.x, a `subscriptions: false` setting should be included on the instantiation of Apollo Server, as follows: -```js line=5-6 +```js{5-6} const server = new ApolloServer({ // Existing configuration typeDefs, @@ -150,7 +150,7 @@ npm install apollo-server-plugin-operation-registry Next, the plugin must be enabled. This requires adding the appropriate module to the `plugins` parameter to the Apollo Server options: -```js line=8-12 +```js{8-12} const server = new ApolloServer({ // Existing configuration typeDefs, @@ -178,10 +178,10 @@ ENGINE_API_KEY= npm start Alternatively, the API key can be specified with the `engine` parameter on the Apollo Server constructor options: -```js line=3 +```js const server = new ApolloServer({ // ... - engine: '' + engine: '' // highlight-line // ... }); ``` @@ -222,7 +222,7 @@ To selectively enable operation safe-listing, the `forbidUnregisteredOperations` For example, to enforce the operation registry safe-listing while skipping enforcement for any request in which the `Let-me-pass` header was present with a value of `Pretty please?`, the following configuration could be used: -```js line=12-27 +```js{12-27} const server = new ApolloServer({ // Existing configuration typeDefs, @@ -259,14 +259,14 @@ const server = new ApolloServer({ We recommend testing the behavior of the plugin, as well as your `forbidUnregisteredOperations` function, before actually forbidding operation execution in production. To do so, you can use the `dryRun` option, which will log information about the operation in lieu of actually forbidding anything. -```js line=7 +```js const server = new ApolloServer({ typeDefs, resolvers, plugins: [ require("apollo-server-plugin-operation-registry")({ forbidUnregisteredOperations: true, - dryRun: true + dryRun: true // highlight-line }); ], }); @@ -294,14 +294,14 @@ This can occur if the schema hasn't been published since the operation registry The first step in debugging the operation registry behavior is to enable debugging. This can be done by enabling the `debug` setting on the plugin within the Apollo Server constructor options: -```js line=7 +```js const server = new ApolloServer({ typeDefs, resolvers, plugins: [ require("apollo-server-plugin-operation-registry")({ // ... other, existing options ... - debug: true, + debug: true, // highlight-line }); ], }); diff --git a/docs/source/platform/schema-registry.md b/docs/source/platform/schema-registry.md index ce6d0bb..1d048e3 100644 --- a/docs/source/platform/schema-registry.md +++ b/docs/source/platform/schema-registry.md @@ -11,7 +11,7 @@ Apollo includes a schema registry that serves as a [central hub](https://princip - Tools like the [Apollo VS Code extension](https://marketplace.visualstudio.com/items?itemName=apollographql.vscode-apollo) can automatically fetch your schema from the registry and provide intellisense like field descriptions and deprecations directly in your editor. - Apollo's registry lets you track related _variants_ of a schema, like staging or alpha versions. It's helpful to have these schema definitions handy without having to juggle running servers that implement them. -

Using the Schema Registry

+## Using the Schema Registry To get started using the schema registry, you'll need to make sure your repository is configured to be an Apollo project by: @@ -26,7 +26,7 @@ Once you have that set up, you'll be ready to start connecting to the schema reg - `apollo service:push`— push a new schema to the registry. - `apollo service:check`— calculate a local schema diff and compare the changes against live traffic to validate if the changes are _safe_ or if they will _break_ live running queries. -

Install the Apollo CLI

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

Get your Engine API key

+### Get your Engine API key To get an API key, you will need to [log in to Engine](https://engine.apollographql.com) and create a new service by clicking the "Add Service" button. If you already have a service, get your API key by visiting your service's settings page. Once you have your API key, add it to your `.env` file like so: @@ -48,7 +48,7 @@ The Apollo CLI will be looking for your `.env` file because it uses your Engine > **Note:** Make sure your `.env` file is in the root of your project so the Apollo CLI knows where to find it. You can also export `ENGINE_API_KEY` as an environment variable. -

Create an `apollo.config.js` file

+### Create an `apollo.config.js` file The commands executed through the Apollo CLI will be looking for your Apollo config to inform their behavior. To set up schema registration, you'll need to configure a source that the CLI can fetch your schema from like so: @@ -66,7 +66,7 @@ module.exports = { The [Apollo config documentation](/docs/references/apollo-config.html#service-config) has more details and advanced configuration options for the `apollo.config.js` format. -

Registering a schema

+## Registering a schema New versions of your schema are registered to Apollo by running the `apollo service:push` command from within your repository. @@ -90,7 +90,7 @@ To get the full value out of Apollo, your graph's schema history should be as ac Here is a sample continuous delivery configuration for pushing a schema to Apollo using CircleCI: -```yaml line=13,29-31 +```yaml{13,29-31} version: 2 jobs: @@ -124,13 +124,13 @@ jobs: fi ``` -

Viewing schema change history

+## Viewing schema change history Changes made to your graph's schema over time can be viewed in [Engine](https://engine.apollographql.com) by browsing to the History page for your graph. Each time you push a new version of your schema, it will appear in your graph's history along with a list of the changes introduced in that version. Schema history page in the Engine UI -

Managing environments

+## Managing environments Product cycles move fast and it's common for schemas to be slightly different across environments as changes make their way through your system. To support this, schemas pushed to the registry can be associated with specific _variants_ of your graph (also referred to _tags_). @@ -138,7 +138,7 @@ Apollo supports tracking multiple _variants_ for every graph. A variant is just To get fully set up associating data sent to Apollo with _variant_ information, you'll need to [configure your CLI commands](#registry-tag) to send data with a `--tag` flag and [configure your Apollo Server](#metrics-tag) with a `schemaTag` option. -

Registering schemas to a variant

+### Registering schemas to a variant To register your schema to a specific _variant_, simply add the `--tag=` flag to your push command: @@ -148,26 +148,26 @@ apollo service:push --tag=beta > **Note:** All schema pushes without a specified tag are registered under the default graph variant, `current`. -

Associating metrics with a variant

+### Associating metrics with a variant There are a few ways to associate metrics reported to [Engine](https://engine.apollographql.com) with a specific variant: 1. The best way to associate metrics with a variant of your graph is to start your server with an environment variable named `ENGINE_SCHEMA_TAG` that contains the name of your variant. This will link metrics sent to Engine with the value of that environment variable. 1. Alternatively, add the `schemaTag` option to your Apollo Server configuration (works for Apollo Server 2.2+): -```js line=5 +```js const server = new ApolloServer({ ... engine: { apiKey: "", - schemaTag: "beta" + schemaTag: "beta" // highlight-line } }); ``` > **Note:** It's important that metrics are associated with the same tag as `service:push` if you want to track isolated data across different variants like production and staging. -

Tools that use the schema registry

+## Tools that use the schema registry Keeping your schema up-to-date in Apollo's registry will ensure that you get the best experience from Apollo's tools that connect to the registry: diff --git a/docs/source/platform/schema-validation.md b/docs/source/platform/schema-validation.md index 1df8307..f20ee66 100644 --- a/docs/source/platform/schema-validation.md +++ b/docs/source/platform/schema-validation.md @@ -9,7 +9,7 @@ Apollo provides a tool to protect for exactly this scenario called **schema vali > **Note:** Schema validation is an Apollo Platform feature available on the [Team and Enterprise plans](https://www.apollographql.com/plans/) of [Apollo Engine](https://engine.apollographql.com). -

How it works

+## How it works Schema validation is run through the Apollo CLI by executing the `apollo service:check` command. Apollo will generate a diff between your local schema and your most recently registered schema, then validate that the changes are safe by checking if any queries actively running against your graph will be affected. @@ -22,7 +22,7 @@ Here's how it works: 1. Engine returns the schema diff and indicates any breaking changes found. 1. The CLI prints the output of this check with a link to view more details in the Engine UI. -

Breaking change detection

+### Breaking change detection Not all schema changes are potentially breaking. Some changes, like adding a field, will always be safe and never cause unexpected behavior for active clients. Other changes, like removing a field or changing a return type, can potentially affect the behavior of clients making queries that use those fields. These are what we consider potentially breaking changes. @@ -178,7 +178,7 @@ A failed `apollo service:check` command will exit with a non-0 exit code and fai Since breaking changes are detected using live traffic, your service will _need active metrics_ for the change algorithm to detect failures. If there are no metrics associated with your service, _all changes will be labeled as a `PASS` as opposed to a `FAIL`_. -

Set up schema validation

+## Set up schema validation To set up schema validation, you wlil need to be both actively sending traces and registering schemas to Apollo: @@ -203,13 +203,13 @@ The command can be placed in any continuous integration pipeline. To surface res > **Note:** The Apollo CLI will be looking in your Apollo config for a location from which to fetch your local schema and using your ENGINE_API_KEY to authenticate its requests with the Engine service. -

Run validation on each commit

+### Run validation on each commit We highly recommended that you add validation to your continuous integration workflow (e.g. Jenkins, CircleCI, etc.). In doing so, you can detect potential problems automatically and display the results of checks directly on pull requests. Here's a example of how to add a schema validation check to CircleCI: -```yaml line=29 +```yaml{26} version: 2 jobs: @@ -240,7 +240,7 @@ jobs: > **Note:** If you're using GitHub status checks, we recommend ignoring the exit code of the `apollo service:check` command so your continuous integration can complete without failing early. This can be done by appending `|| echo 'validation failed'` to the command call. -

GitHub integration

+### GitHub integration
@@ -270,7 +270,7 @@ The output of `apollo service:check --markdown` looks like this: 🔗 [View your service check details](https://engine.apollographql.com/service/engine/checks?...). ``` -

Multiple environments

+### Multiple environments Product cycles move fast and it's common for schemas to be slightly different across environments as changes make their way through your system. To support this, schemas pushed to the registry can be associated with specific _variants_ of your graph (also referred to tags). @@ -282,7 +282,7 @@ Variants mostly commonly represent environments and can also indicate branches o
-

Adjusting validation parameters

+## Adjusting validation parameters Depending on the requirements of your application, you may want to configure the timeframe to validate operations against. You can do so by providing a `validationPeriod` flag to the CLI. The timeframe will always end at "now", and go back in time by the amount specified. diff --git a/docs/source/references/apollo-config.md b/docs/source/references/apollo-config.md index 48f82e6..ce623e8 100644 --- a/docs/source/references/apollo-config.md +++ b/docs/source/references/apollo-config.md @@ -9,13 +9,13 @@ If you're using one of our workflow tools like the Apollo CLI or the Apollo VS C There are two types of projects, `client` and `service`, which can be in the same configuration file if necessary. This document describes all the options available in the Apollo config and defines which are required vs. optional. -

Client projects

+## Client projects Client projects are configured through a top level `client` key in the config. -```js line=2 +```js module.exports = { - client: { ... }, + client: { ... }, // highlight-line }; ``` @@ -35,7 +35,7 @@ To link your client to a schema through the Apollo schema registry, you'll need With Engine set up, you can point your client directly to your graph's schema by putting your graph's Engine ID in your Apollo config, like so: -```js line=3 +```js{3} module.exports = { client: { service: 'my-apollo-service' // the id of your service in Engine (from the URL) @@ -47,7 +47,7 @@ module.exports = { If you're tracking different versions of your schema in the registry using schema variants, you can link your client to a specific variant like so: -```js line=3 +```js{3} module.exports = { client: { service: 'my-apollo-service@staging' // "staging" is the schema variant we're using @@ -61,7 +61,7 @@ If a schema variant is not specified, Apollo tools will fall back to the default Remote endpoints can be used to pull down a schema from a running service. This can be configured like so: -```js line=3-11 +```js{3-11} module.exports = { client: { service: { @@ -82,7 +82,7 @@ module.exports = { In some cases you may have a locally generated file with your schema that you want to link. This can be either a `.graphql` file with the schema in SDL form or a saved introspection result in `.json`. To link your client project to a local schema file, configure it like so: -```js line=3-6 +```js{3-6} module.exports = { client: { service: { @@ -99,7 +99,7 @@ _Optional_ –– by default, Apollo tools will look under a `./src` directory t Client projects often contain client-side schema definitions for local state with Apollo Client. To make sure the Apollo CLI and VS Code extension can find these files and read them correctly, you may need to tell Apollo which folders to look for your schema and queries in like so: -```js line=3 +```js{3} module.exports = { client: { includes: ['./imports/**/*.js'], // array of glob patterns @@ -114,7 +114,7 @@ _Optional_ –– by default, Apollo tools will exclude `**/node_modules` and `* If you want Apollo to ignore any of your other folders when looking for queries and schema definitions, adjust your config like so: -```js line=3 +```js{3} module.exports = { client: { excludes: ['**/__tests__/**/*'], // array of glob patterns @@ -129,10 +129,10 @@ _Optional_ –– custom tagged template literal. When using GraphQL with JavaScript or TypeScript projects, it is common to use the `gql` tagged template literal to write out operations. Apollo tools will be looking through your files for the `gql` tag to extract your queries, so if you use a different template literal, you can configure it like so: -```js line=3 +```js module.exports = { client: { - tagName: "graphql", + tagName: "graphql", // highlight-line service: ... } }; @@ -144,10 +144,10 @@ _Optional_ –– Apollo will by default add the `__typename` field to all your GraphQL clients like Apollo Client often add the `__typename` field to operations automatically when they're sent over the wire. This can come in really handy for things like caching, but it can be turned off by adding `addTypename: false` to the client config: -```js line=3 +```js module.exports = { client: { - addTypename: false, + addTypename: false, // highlight-line service: ... } }; @@ -166,7 +166,7 @@ _Optional_ –– By default, Apollo projects support the following client-side Client side applications can use custom directives on their queries that aren't meant to be sent to the server. Configuration of client side directives beyond the defaults listed above can be set up like so: -```js line=3-4 +```js{3-4} module.exports = { client: { clientOnlyDirectives: ["connection", "type"], @@ -180,13 +180,13 @@ module.exports = { `clientSchemaDirectives` are directives that indicate a portion of the operation that is not meant to be sent to the server. These directives are removed as well as the fields they are placed on. An example of this type of directive is the `@client` directive. -

Server projects

+## Server projects Server projects are configured through a top level `service` key in the config. -```js line=2 +```js module.exports = { - service: { ... }, + service: { ... }, // highlight-line }; ``` @@ -195,11 +195,11 @@ Defining a `service` key in your Apollo config will provide the CLI with the inf 1. Using a remote endpoint 1. Using a local schema file -

Option 1: Remote endpoint

+#### Option 1: Remote endpoint Remote endpoints can be used to pull down a schema from a running service. This can be configured like so: -```js line=2-10 +```js{2-10} module.exports = { service: { endpoint: { @@ -214,11 +214,11 @@ module.exports = { }; ``` -

Option 2: Local schema

+#### Option 2: Local schema In some cases you may have a locally generated file with your schema that you want to link. This can be either a `.graphql` file with the schema in SDL form or a saved introspection result in `.json`. To link your client project to a local schema file, configure it like so: -```js line=3 +```js module.exports = { service: { localSchemaFile: './path/to/schema.graphql' diff --git a/docs/source/references/apollo-engine.md b/docs/source/references/apollo-engine.md index 1404964..ee9a30f 100644 --- a/docs/source/references/apollo-engine.md +++ b/docs/source/references/apollo-engine.md @@ -11,11 +11,11 @@ More information on pricing and billing can be found [here](https://www.apollogr ![The Apollo Engine Architecture](../img/apollo-engine/engine-architecture.png) -

Accounts

+## Accounts Engine accounts are authenticated using GitHub by default. We also offer single sign-on (SAML or OIDC) to our [Enterprise](https://www.apollographql.com/plans/) customers. -

Team collaboration

+### 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. @@ -25,36 +25,30 @@ When you sign in to Engine, you will have access to all the teams where you're a 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

+### 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 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. - - -

Graphs

+## Graphs A _graph_ (formerly called _service_) in Engine represents a _project_ or _application_. When you create a new graph, we provide an API key used to send performance metrics and schema versions to our cloud service. This information is then accessible through the Engine interface. -

Creating a graph

+### Creating a graph To create a graph, you will need to select an account for that graph to belong to. All members of the account will be able to see the graph's data and settings options. You can transfer graphs between any of your Engine accounts by visiting its Settings page and change the “owner” to whichever account you’d like. Graphs in Engine have globally unique IDs. We recommend that you prefix your ID with the name of your company or organization to avoid naming collisions with other graphs in the system. -

Managing environments

+### Managing environments Each graph in Engine should represent a single application, and environments within your application should be tracked using [_variants_](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 variants within Engine. @@ -64,11 +58,11 @@ API keys can be added and removed from a graph at any time. They are used to bot You can manage your API keys on your graph's settings page. It is 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

+## Data privacy All data that is sent to Engine from your server can be configured and turned off to meet your data privacy needs. This section will walk through what information Engine sees about your GraphQL graph's requests, 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

+### 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: @@ -89,7 +83,7 @@ As your clients make requests to your server, the proxy reads response extension 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 sent by 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

+### Data collection This section describes which parts of your GraphQL HTTP requests are seen and collected by Engine. @@ -113,11 +107,11 @@ Engine will **never** collect your application's `Authorization`, `Cookie`, or ` 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

+### Response Let’s walk through Engine’s default behavior for reporting on fields in a typical GraphQL response: -``` +```json // GraphQL Response { "data": { ... }, // Never sent to the Engine cloud service @@ -157,7 +151,7 @@ GDOR ###################################################################### --> -

GDPR

+## 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. @@ -192,7 +186,7 @@ The legal terms and policies that apply to Apollo's corporate websites and custo #### Where can I get more help? -If you have any questions (including interest in a Data Processing Addendum or DPA), or encounter any issues, please reach out to support. +If you have any questions (including interest in a Data Processing Addendum or DPA), or encounter any issues, please reach out to [support](https://engine.apollographql.com/support). -

Policies and Agreements

+## 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/references/engine-proxy-1.0-migration.md b/docs/source/references/engine-proxy-1.0-migration.md index 6a20691..f34978c 100644 --- a/docs/source/references/engine-proxy-1.0-migration.md +++ b/docs/source/references/engine-proxy-1.0-migration.md @@ -6,7 +6,7 @@ title: Upgrade to apollo-engine 1.0 Version 1.0 of the npm `apollo-engine` package replaces the `Engine` API with a streamlined `ApolloEngine` API. It's straightforward to upgrade your app to the 1.0 API. -

Migrating from `Engine` to `ApolloEngine`

+## Migrating from `Engine` to `ApolloEngine` A typical use of the pre-1.0 `Engine` API with an Express server looked like: @@ -73,8 +73,7 @@ Notable differences: For full details including an API reference, see [the Node setup guide](./setup-node.html). - -

Behind the scenes

+### Behind the scenes The old API was based on "double proxying". If your web server was supposed to serve on port 4000, you would tell Express (or your other web framework) to listen on port 4000. The `Engine` class would start an instance of the Engine Proxy running on an ephemeral port (say, 4321). You would add a special middleware to your framework which redirects GraphQL requests to `127.0.0.1:4321`. The Engine Proxy would then make GraphQL requests back to your Node server on port 4000. The middleware used a special header to differentiate between the initial request from an external client and the nearly-identical internal request from Engine. So GraphQL requests are routed `client -> Node -> Engine Proxy -> Node` and non-GraphQL requests are routed `client -> Node`. @@ -89,7 +88,7 @@ This resolves all of the problems listed above. Because there's no "middleware" This does mean that *all* of the HTTP traffic on your server is now routed through the Engine Proxy, whereas before non-GraphQL traffic avoided that hop. The Engine Proxy uses the industry-standard Go reverse proxy library to transparently proxy non-GraphQL HTTP and Websocket traffic, so you should observe no major difference. If you do find any problems from running non-GraphQL traffic through the Engine Proxy, please [let us know](https://engine.apollographql.com/login?overlay=SupportRequestNoAccount), or consider running your GraphQL server separately from other servers. -

Upgrading the Docker container to v1 and a new way to run the proxy

+## Upgrading the Docker container to v1 and a new way to run the proxy While most pre-v1 Apollo Engine users use the `Engine` API from the `apollo-engine` npm module to run Engine against Node origins, we also provide the Engine Proxy in a Docker container. This is primarily intended for use with non-Node GraphQL servers. @@ -102,7 +101,7 @@ The Docker container is mostly unchanged in v1. Here's what's new: - If you configure a frontend endpoint as `/graphql`, requests to `/graphql/` should be served also. (This previously worked if you were using the `Engine` double proxy mode but not with the Docker container.) -

Automatic cache store configuration

+## Automatic cache store configuration Prior to Engine v1, the features that require an in-memory or memcached cache store ([public and private full-query response cache](./caching.html), [automatic persisted queries](./auto-persisted-queries.html), and the session token authorization cache) required you to manually configure a cache store and enable them. diff --git a/docs/source/references/engine-proxy.md b/docs/source/references/engine-proxy.md index 243112c..9300549 100644 --- a/docs/source/references/engine-proxy.md +++ b/docs/source/references/engine-proxy.md @@ -46,7 +46,7 @@ You can test that you’ve correctly enabled Apollo Tracing by running any query The `tracing` field should now be returned as part of the response's `extensions` like below. Don’t worry, this data won’t make it back to your clients once you've set up the Engine proxy, because the proxy will filter it out. -```js line=3-5 +```js{3-5} { "data": { ... }, "extensions": { @@ -71,10 +71,7 @@ Apollo distributes the Engine proxy in two forms: as an **npm package** and as a 1. [Run the proxy through a Platform as a Service (eg. Heroku)](#platform-as-a-service) 1. [Run the proxy in a serverless environment (eg. Lambda)](#serverless) -

- -Option 1: Running the proxy with Apollo Server -

+#### Option 1: Running the proxy with Apollo Server The two cases where you should be running the Engine proxy with Apollo Server are: @@ -136,10 +133,7 @@ engine.listen({ Engine is now wrapping your endpoint and processing your GraphQL requests and responses like normal. If you call your endpoint again, your requests will be routed through the Engine proxy to your server and back. If everything is working, you will no longer see `tracing` data in your responses because your Engine proxy is filtering and processing that information for you. -

- -Option 2: Running a standalone proxy using Node -

+#### Option 2: Running a standalone proxy using Node Even if your GraphQL server is not implemented with Node, you may find it easier to run a tiny Node program in your hosting environment than to run a Docker container. If so, this proxy deployment option is for you. @@ -192,10 +186,7 @@ If you run this program with Node, the proxy will start up and start accepting c If you open up GraphiQL on http://localhost:3000, you'll notice that the `tracing` extension data is no longer in the result of your query. This is because Engine is consuming it! You can verify that everything is working correctly by checking the Engine UI for your new service and confirming that you see data in the Metrics section. -

- -Option 3: Running a standalone proxy with Docker -

+#### Option 3: Running a standalone proxy with Docker The Engine proxy is also distributed as a Docker image that you can deploy and manage separate from your server. It does not matter where you choose to deploy and manage your proxy, though it's more efficient if your proxy is located on the same machine or network as your GraphQL server. @@ -235,16 +226,13 @@ The Proxy should start up and accept connections at http://localhost:3000 and fo You can find the complete documentation for Engine configuration options on the [full API docs](./proxy-config.html) page, and some commonly-used fields worth knowing about are described in the [`new ApolloEngineLauncher()` docs](#api-apollo-engine-launcher). -

- -Option 4: Running the proxy through a Platform as a Service (eg. Heroku) -

+#### Option 4: Running the proxy through a Platform as a Service (eg. Heroku) It may be most convenient for you to run and host the Engine proxy outside your app's deployment altogether. If that is the case, automatically running the proxy on a Platform as a Service like Heroku might be the easiest option for you. We have an example repository with a guide for [running the Engine proxy on Heroku](https://github.com/apollographql/engine-heroku-example) that you can follow along in. Like running a [standalone proxy with Docker](#standalone-proxy-with-docker), you'll need to configure your proxy with an `engine-config.json` file like so: -``` +```json { "apiKey": "", "origins": [ @@ -271,10 +259,7 @@ We have an example repository with a guide for [running the Engine proxy on Hero It does not matter where you choose to deploy and manage your Engine proxy. We've built this guide for Heroku because they have an easy deployment mechanism for Docker containers, but we run our own Engine proxy on Amazon's [EC2 Container Service](https://aws.amazon.com/ecs/). -

- -Option 5: Running the proxy in a serverless environment (eg. Lambda) -

+#### Option 5: Running the proxy in a serverless environment (eg. Lambda) Last but not least, you may be wondering how to use Engine if you run your application in a serverless environment like Lamdba. If so, this is the guide for you! @@ -292,7 +277,7 @@ The proxy needs to be run separately from your function because it's responsible The main difference between setting up the proxy to work with cloud functions versus setting it up with a persistent server is in how you configure it. You'll want an `engine-config.json` that looks something like this: -``` +```json { "apiKey": "", "origins": [ @@ -329,7 +314,7 @@ The following proxy features require specific setup steps to get working. 1. [Integrating with your **CDN**](#cdn) 1. [Using the Engine proxy with **query batching**](#query-batching) -

Automatic Persisted Queries (APQ)

+### Automatic Persisted Queries (APQ) Automatically persisting your queries is a performance technique in which you send a query hash to your server instead of the entire GraphQL query string. Your server keeps track of the map between these hashes and their full query strings and does the lookup on its end, saving you the bandwidth of sending the full query string over the wire. @@ -344,21 +329,21 @@ To use automatic persisted queries with the Engine proxy: - Use Engine proxy `v1.0.1` or newer. - If your GraphQL server is hosted on a different origin domain from where it will be accessed, setup the appropriate [CORS headers](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) using the `overrideGraphqlResponseHeaders` object on the proxy's `frontend` configuration: - ```javascript - frontends: [{ - overrideGraphqlResponseHeaders: { - 'Access-Control-Allow-Origin': '*', - }, - }], - ``` - -- Configure your client to use APQs. If you're using Apollo Client, you can easily use [`apollo-link-persisted-queries`](https://github.com/apollographql/apollo-link-persisted-queries#automatic-persisted-queries) to set this up. - - +```javascript +frontends: [{ + overrideGraphqlResponseHeaders: { + 'Access-Control-Allow-Origin': '*', + }, +}], +``` + +* Configure your client to use APQs. If you're using Apollo Client, you can easily use [`apollo-link-persisted-queries`](https://github.com/apollographql/apollo-link-persisted-queries#automatic-persisted-queries) to set this up. + + If everything is set up correctly, you should see your client sending hashes insteady of query strings over the network, but receiving data as if it had sent a normal query. -

Caching

+### Caching To bring caching to GraphQL we've developed [Apollo Cache Control](https://github.com/apollographql/apollo-cache-control), an open standard that allows servers to specify exactly which parts of a response can be cached and how long they can be cached for. @@ -374,19 +359,16 @@ There are just a few steps to enable response caching in Engine proxy, and one o 1. [Annotate your schema and/or resolvers with cache control hints.](#annotate-your-responses) 1. [Optional: Configure cache options in your Engine Proxy configuration.](#configure-cache-options) -

- -1. Add `cacheControl` extensions to your sevrer -

+#### 1. Add `cacheControl` extensions to your sevrer If you're using Apollo Server for your Node GraphQL server, the only server code change required is to add `cacheControl: true` to the options passed to your Apollo Server configuration. -```js line=5,12 +```js // Apollo Server 2: const server = new ApolloServer({ typeDefs, resolvers, - cacheControl: true + cacheControl: true // highlight-line }); // Apollo Server 1.2 and onwards: @@ -396,17 +378,14 @@ app.use( graphqlExpress({ schema, context: {}, - cacheControl: true + cacheControl: true // highlight-line }) ); ``` We're working with the community to add support for Apollo Cache Control to non-Node GraphQL server libraries. Contact us at suppot@apollogrqphql.com if you're interested in joining the community to work on support for `express-graphql` or non-Node GraphQL servers. -

- -2. Add cache hints to your responses -

+#### 2. Add cache hints to your responses Next we'll add some cache hints to our GarphQL responses. There are two ways to do this -- either dynamically in your resolvers or statically on your schema types and fields. Each `cacheControl` hint has two parameters: @@ -467,7 +446,7 @@ type Author @cacheControl(maxAge: 60) { You should receive cache control data in the `extensions` field of your response: -```js +```json "cacheControl": { "version": 1, "hints": [ @@ -573,10 +552,7 @@ app.use( Setting `defaultMaxAge` requires `apollo-server-*` 1.3.4 or newer. -

- -3. Optional: Configure cache options -

+#### 3. Optional: Configure cache options As long as you're using a version of the Engine proxy that's greater than `1.0`, you won't have to configure anything to use public response caching. The proxy comes with a default 50MB in-memory cache. To enable private response caching or to configure details of how caching works, there are a few fields in the Engine configuration (ie, argument to `new ApolloServer`) that are relevant. @@ -686,7 +662,7 @@ Engine will never decide to cache responses in its response cache unless you tel When returning a GraphQL response which is eligible for the full-query cache (ie, all of the data has a non-zero `maxAge` set in the `cacheControl` GraphQL extension), Engine sets the `Cache-Control` header with a `max-age` directive equal to the minimum `maxAge` of all data in the response. If any of the data in the response has a `scope: PRIVATE` hint, the `Cache-Control` header will include the `private` directive; otherwise it will include the `public` directive. This header completely replaces any `Cache-Control` and `Expires` headers provided by your GraphQL server. -

CDN integration

+### CDN integration Many high-traffic web services use content delivery networks (CDNs) such as [Cloudflare](https://www.cloudflare.com/), [Akamai](https://www.akamai.com/) or [Fastly](https://www.fastly.com/) to cache their content as close to their clients as possible. @@ -710,7 +686,7 @@ To do this, follow the steps in the [guide above](#automatic-persisted-queries). How precisely this works relies upon which CDN you chose. Configure your CDN to send requests to your Engine proxy-powered GraphQL app. For some CDNs, you may need to specially configure your CDN to honor origin Cache-Control headers. For example, here is [Akamai's documentation on that setting](https://learn.akamai.com/en-us/webhelp/ion/oca/GUID-57C31126-F745-4FFB-AA92-6A5AAC36A8DA.html). If all is well, your cacheable queries should now be cached by your CDN! Note that requests served directly by your CDN will not show up in your Engine dashboard. -

Query batching

+### Query batching Query batching allows your client to batch multiple queries into one request. This means that if you render several view components within a short time interval, for example a navbar, sidebar, and content, and each of those do their own GraphQL query, the queries can be sent together in a single roundtrip. @@ -844,7 +820,7 @@ const engine = new ApolloEngine({ Test that you enabled Apollo Tracing by checking if your GraphQL server returns trace extensions in GraphQL responses when not executed through Engine. If it does, it's is a sign that Apollo Tracing is properly configured. -

Troubleshooting FAQs

+### Troubleshooting FAQs #### I'm getting an error saying “The query failed!”, how do I fix it? @@ -862,7 +838,7 @@ There is a health check URL at `[engine-frontend-url]/.well-known/apollo/engine- Each time the Engine proxy starts, you should see the following two lines in the logs indicating the Engine proxy is healthy: -``` +```console INFO[0000] Started HTTP server. address="[::]:50485" INFO[0000] Engine proxy started. version=2018.02-93-ge050c6b93 ``` @@ -877,7 +853,7 @@ const engine = new ApolloEngine({ }); ``` -

Submit a support ticket

+### Submit a support ticket Please include the following when submitting an issue to our support team: diff --git a/docs/source/references/setup-analytics.md b/docs/source/references/setup-analytics.md index 1ae5468..ed1fb87 100644 --- a/docs/source/references/setup-analytics.md +++ b/docs/source/references/setup-analytics.md @@ -5,7 +5,7 @@ description: Turn on metrics reporting to get performance and schema usage insig GraphQL offers a number of interesting insights in the realm of server performance and usage monitoring. Because the structure of GraphQL queries requires clients to request exactly the fields they need, simple instrumentation allows us to elicit exactly which fields in the schema are being used at any given time. This helps us understand how much usage different parts of our data model get at a far more granular level than we could achieve out of the box with non-GraphQL APIs. -

Tracing query execution

+#### Tracing query execution A "trace" corresponds to exactly one [GraphQL operation](https://www.apollographql.com/docs/resources/graphql-glossary.html#operation) and represents a breakdown of timing and error information for each individual field resolved as part of that operation. @@ -13,12 +13,12 @@ By recording which resolvers executed in our server and their traces, we can bui We've specifically built an interface to view this information into [Apollo Engine](https://engine.apollographql.com/) and any GraphQL server can report metrics to Engine by sending data in the `apollo-tracing` format to our metrics ingress. Read on to learn how to set this up in your environment. -

Apollo Server

+## Apollo Server Apollo Server has had the ability to report its performance usage metrics to Engine built-in. To set it up, get an API key from [Engine](https://engine.apollographql.com/) by logging in and creating a graph. Then set your API key in the `ENGINE_API_KEY` environment variable or pass it into your Apollo Server constructor like so: -```js line=6-8 -const { ApolloServer } = require('apollo-server'); +```js{6-8} +const { ApolloServer } = require("apollo-server"); const server = new ApolloServer({ typeDefs, @@ -35,7 +35,7 @@ server.listen().then(({ url }) => { For advanced configuration options to set up logging, error filtering, and client-aware metrics reporting take a look at our [server documentation](https://www.apollographql.com/docs/apollo-server/features/metrics.html). -

Other servers

+## Other servers There are 2 ways to send metrics data from your server to Engine: @@ -55,7 +55,7 @@ There are four steps to creating a reporting agent for any server: 3. Emitting batches of Traces to the reporting endpoint 4. Providing plugins for more advanced reporting functionality -

1. Tracing Format

+### 1. Tracing Format The first step of creating a metrics reporting agent will be to hook into the GraphQL execution pipeline to create the metrics and translate them into the proper data format. @@ -69,13 +69,13 @@ As a good starting point, we recommend implementing an extension to the GraphQL An example of a FullTracesReport message, represented as JSON, can be found below\* -

2. Operation Signing

+### 2. Operation Signing In order to correctly group GraphQL operations, it's important to define a method for "signing" a query. Because GraphQL queries can be expressed in a variety of ways, this is a harder problem than it may appear to be at first thought. For instance, even though all of the following queries request the same information, it's ambiguous whether they should be treated equally. -```gql +```graphql query AuthorForPost($foo: String!) { post(id: $foo) { author @@ -111,7 +111,7 @@ Even though this concept lacks definition, it's important to decide on how queri The TypeScript reference implementation uses a default signature method and allows for that signature method to also be overridden by the user. The [implementation of the default](https://github.com/apollographql/apollo-server/blob/master/packages/apollo-engine-reporting/src/signature.ts) drops unused fragments and/or operations, hides String literals, ignores aliases, sorts the tree deterministically, and ignores whitespace differences. We recommend using the same default signature method for consistency across different server runtimes. -

3. Sending Metrics

+### 3. Sending Metrics Once a metrics report (i.e. batch of traces) is prepared, it will need to be sent to an ingress for aggregation and sampling. Currently, this is all performed in Apollo's cloud services. The endpoint for this aggregation and sampling is at `https://engine-report.apollodata.com/api/ingress/traces`, which supports the protobuf format mentioned above via a `POST` request. The reporting endpoint accepts a gzipped body as well. To see the full reference implementation, see the `sendReport()` method in the [TypeScript reference agent](https://github.com/apollographql/apollo-server/blob/master/packages/apollo-engine-reporting/src/agent.ts#L210). @@ -121,7 +121,7 @@ We recommend implementing retries with backoff on 5xx responses and network erro > NOTE: In the future, we plan to release a local aggregation and sampling agent that could be used to lessen the bandwidth requirements on reporting agents. -

4. [Optional] Advanced Reporting Features

+### 4. [Optional] Advanced Reporting Features The reference TypeScript implementation also includes several more advanced features which may be worth porting to new implementations. All of these features are implemented in the agent itself and are documented in the interface description for the EngineReportingOptions of [the agent](https://github.com/apollographql/apollo-server/blob/master/packages/apollo-engine-reporting/src/agent.ts#L51). @@ -129,7 +129,7 @@ For example, the option to send reports immediately may be particularly useful t Another important feature is the ability to limit information sent, particularly to avoid reporting [personal data](https://en.wikipedia.org/wiki/Personal_data). Because the most common place for personal data to appear is in variables and headers, the TypeScript agent offers options for `privateVariables` and `privateHeaders`. -

Example FullTracesReport, represented as JSON

+### Example FullTracesReport, represented as JSON ```json { diff --git a/docs/source/resources/graphql-glossary.md b/docs/source/resources/graphql-glossary.md index 6bf7db6..365f780 100644 --- a/docs/source/resources/graphql-glossary.md +++ b/docs/source/resources/graphql-glossary.md @@ -5,19 +5,19 @@ description: A comprehensive list of important GraphQL words and acronyms When you start diving into the GraphQL ecosystem, you'll probably encounter some unfamiliar terms and phrases along the way. To help you on your journey, we've defined some of the most common GraphQL vocabulary here in this handy cheat sheet. -

Apollo

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

Automatic Persisted Queries (APQ)

+## Automatic Persisted Queries (APQ) A technique for improving GraphQL network performance with zero build-time configuration by reducing request size over the wire. A smaller signature reduces bandwidth utilization and speeds up client loading times. Apollo Server allows implementation of [Automatic Persisted Queries (APQ)](https://www.apollographql.com/docs/guides/performance.html#automatic-persisted-queries). -

Argument

+## Argument A set of key-value pairs attached to a specific field. Arguments can be literal values or variables. -```js +```graphql { human(id: "200") { weight(unit: "pounds") @@ -28,11 +28,11 @@ A set of key-value pairs attached to a specific field. Arguments can be literal `id` is an argument to human in the query above. -

Alias

+## Alias An alternative name given to the result of a field to avoid conflicts during data fetching. -```js +```graphql { admins: users(role: "admin") { id @@ -49,15 +49,15 @@ An alternative name given to the result of a field to avoid conflicts during dat `admins` and `managers` are aliases in the example query above. -

Data Source

+## Data Source A new pattern for fetching data from a particular service, with built-in support for caching, deduplication, and error handling. When deploying GraphQL as a layer between your apps and existing APIs and services, [Data sources](https://www.apollographql.com/docs/apollo-server/v2/features/data-sources.html) provide the best experience for fetching and caching data from REST endpoints. -

Deferred query

+## Deferred query A query that has certain fields tagged with the [`@defer` directive](https://www.apollographql.com/docs/react/features/defer-support.html), so that fields that take a long time to resolve do not need to slow down the entire query. -```js +```graphql query NewsFeed { newsFeed { stories { @@ -70,22 +70,22 @@ query NewsFeed { } ``` -

Directive

+## Directive A declaration prefixed with an `@` character that encapsulates programming logic for query execution on the client or server. There are built-in directives such as `@skip` or `@include`, and [custom directives](https://www.apollographql.com/docs/graphql-tools/schema-directives.html). Directives can be used for features such as authentication, incremental data loading, etc. -```js +```graphql type User @auth { name: String! banned: Boolean @auth! } ``` -

Docstring

+## Docstring It is used for providing descriptions of types, fields and arguments. Docstrings show up in the documentation panel inside GraphQL playground and GraphiQL. -```js +```graphql """ Description for the User """ @@ -104,19 +104,19 @@ type User { } ``` -

Document

+## Document A file or request string that contains one or multiple definitions of a GraphQL type system and can be interpreted by a GraphQL execution engine. -

Extensions

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

Field

+## Field A unit of data you are asking for in a Schema, which ends up as a field in your JSON response data. -```js +```graphql type Author { id: Int! firstName: String @@ -126,11 +126,11 @@ type Author { `id`, `firstName`, and `lastName` are fields in the Author type above. -

Fragment

+## Fragment A selection set that can be reused in multiple query operations. A [GraphQL fragment](https://www.apollographql.com/docs/react/advanced/fragments.html) is a shared piece of query logic. -```js +```graphql fragment UserData on User { id: ID! firstName: String! @@ -144,7 +144,7 @@ query getUsers { } ``` -

gql function

+## gql function A [JavaScript template literal tag](https://github.com/apollographql/graphql-tag) that parses GraphQL queries into an abstract syntax tree (AST). @@ -158,23 +158,23 @@ const typeDefs = gql` `; ``` -

GraphQL Playground

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

GraphQL Service

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

GraphiQL

+## GraphiQL An in-browser IDE for GraphQL development. -

Introspection

+## Introspection A technique to provide detailed information about a GraphQL API's schema. Types and fields used in introspection are prefixed with "\_\_" two underscores. -```js +```graphql { __schema { types { @@ -184,11 +184,11 @@ A technique to provide detailed information about a GraphQL API's schema. Types } ``` -

Mutation

+## Mutation An operation for creating, modifying and destroying data. -```js +```graphql mutation AddTodo($type: String!) { addTodo(type: $type) { id @@ -197,7 +197,7 @@ mutation AddTodo($type: String!) { } ``` -

Normalization

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

Object Type

+## Object Type A type in a GraphQL schema that has fields. -```js +```graphql type User { name: String! } @@ -230,15 +230,15 @@ type User { `User` is an Object type in the example above. -

Operation

+## Operation A single query, mutation, or subscription that can be interpreted by a GraphQL execution engine. -

Operation name

+## Operation name A name for a single query, mutation, or subscription. Identifying a query or mutation by name is very useful for logging and debugging when something goes wrong in a GraphQL server. -```js +```graphql mutation AddTodo($type: String!) { addTodo(type: $type) { id @@ -256,19 +256,19 @@ query getHuman { `AddTodo` and `getHuman` are names for the mutation and query operation respectively. -

Partial query caching

+## Partial query caching A technique for caching inputs to GraphQL queries. This type of caching ensures that if the query is slightly different but with the same inputs, those inputs can simply be retrieved from the cache instead of fetching data again from the backend. It is implemented in Apollo Server 2 as [Data Source](https://www.apollographql.com/docs/apollo-server/features/data-sources.html) caching. -

Query

+## Query A read-only fetch operation to request data from a GraphQL service. -

Query colocation

+## Query colocation A practice of placing a GraphQL query in the same location as the app component's view logic. Query co-location makes it easier to facilitate a smooth UI and chore of data retrieval. Jumping directly to the query and keeping the component in sync with its data dependencies is a pleasure. -```js +```jsx const GET_DOG_PHOTO = gql` query dog($breed: String!) { dog(breed: $breed) { @@ -289,16 +289,15 @@ export const queryComponent = ({ breed }) => ( ); ``` -

Query whitelisting

+## Query whitelisting A technique for preventing unwanted attacks by maintaining a list of approved queries that are allowed in your application. Any query not present in the list that is run against the server will not be allowed. [Automatic Persisted Queries](../guides/performance.html#automatic-persisted-queries) is a feature of Apollo Server 2 that enables query whitelisting and persisted queries. -

Resolver

+## Resolver A function that connects schema fields and types to various backends. Resolvers provide the instructions for turning a GraphQL operation into data. It can retrieve data from or write data to anywhere, including a SQL, No-SQL, or graph database, a micro-service, and a REST API. Resolvers can also return strings, ints, null, and other primitives. ```js -... const resolvers = { Query: { author(root, args, context, info) { @@ -313,54 +312,56 @@ const resolvers = { }; ``` -

Schema

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

Schema Definition Language (SDL)

+## Schema Definition Language (SDL) The syntax for writing GraphQL Schemas. It is otherwise known as Interface Definition Language. It is the lingua franca shared by all for building GraphQL APIs regardless of the programming language chosen. -```js +```graphql type Author { id: Int! firstName: String lastName: String posts: [Post] } + type Post { id: Int! title: String author: Author votes: Int } + type Query { posts: [Post] author(id: Int!): Author } ``` -

Schema first development

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

Schema registry

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

Schema versioning

+## Schema versioning Refers to the need to evolve a schema over time. As a schema evolves, there is a potential for introducing breaking changes to clients. The Apollo CLI assists schema evolution by validating schema changes and checking for breaking changes using Apollo Engine. Read more in our article about [schema change validation](https://www.apollographql.com/docs/platform/schema-validation#versioning). -

Schema stitching

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

Subscription

+## Subscription A real-time GraphQL operation. A [Subscription](https://www.apollographql.com/docs/apollo-server/features/subscriptions.html) is defined in a schema along with queries and mutations. -```js +```graphql type Subscription { commentAdded(repoFullName: String!): Comment } @@ -373,15 +374,15 @@ subscription onCommentAdded($repoFullName: String!){ } ``` -

Scalar Type

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

Type System

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

Variable

+## Variable A value that can be passed to an operation. Variables can be used to fill arguments, or be passed to directives. @@ -410,6 +411,6 @@ In `react-apollo` it would be passed like this: ``` -

Whole response caching

+## 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. Read more about GraphQL query caching in our [guide for caching with Apollo Server](https://www.apollographql.com/docs/apollo-server/features/caching). diff --git a/docs/source/tutorial/client.md b/docs/source/tutorial/client.md index 8fec162..8debc16 100644 --- a/docs/source/tutorial/client.md +++ b/docs/source/tutorial/client.md @@ -9,7 +9,7 @@ The next half of this tutorial exclusively focuses on connecting a graph API to While Apollo Client works with any view layer, it's most commonly used with React. In this section, you'll learn how to connect the graph API you just built in the previous half of this tutorial to a React app. Even if you're more comfortable with Vue or Angular, you should still be able to follow many of the examples since the concepts are the same. Along the way, you'll also learn how to build essential features like authentication and pagination, as well as tips for optimizing your workflow. -

Set up your development environment

+## Set up your development environment For this half of the tutorial, we will be working in the `client/` folder of the project. You should have the project already from the server portioned, but if you don't, make sure to clone [the tutorial](https://github.com/apollographql/fullstack-tutorial/). From the root of the project, run: @@ -23,7 +23,7 @@ Now, our dependencies are installed. Here are the packages we will be using to b - `react-apollo`: The view layer integration for React that exports components such as `Query` and `Mutation` - `graphql-tag`: The tag function `gql` that we use to wrap our query strings in order to parse them into an AST -

Configure Apollo VSCode

+### Configure Apollo VSCode While Apollo VSCode is not required to successfully complete the tutorial, setting it up unlocks a lot of helpful features such as autocomplete for operations, jump to fragment definitions, and more. @@ -54,7 +54,7 @@ module.exports = { Great, we're all set up! Let's dive into building our first client. -

Create an Apollo Client

+## Create an Apollo Client Now that we have installed the necessary packages, let's create an `ApolloClient` instance. @@ -73,16 +73,16 @@ const cache = new InMemoryCache(); const link = new HttpLink({ uri: 'http://localhost:4000/' }) + const client = new ApolloClient({ cache, link }) - ``` In just a few lines of code, our client is ready to fetch data! Let's try making a query in the next section. -

Make your first query

+## Make your first query Before we show you how to use the React integration for Apollo, let's send a query with vanilla JavaScript. @@ -90,13 +90,15 @@ With a `client.query()` call, we can query our graph's API. Add the following li _src/index.js_ -```js line=1 -import gql from "graphql-tag"; +```js +import gql from "graphql-tag"; // highlight-line ``` + And add this code to the bottom of `index.js`: _src/index.js_ -``` + +```js // ... above is the instantiation of the client object. client .query({ @@ -120,7 +122,7 @@ Apollo Client is designed to fetch graph data from any JavaScript frontend. No f Go ahead and delete the `client.query()` call you just made and the `gql` import statement. Now, we'll connect our client to React. -

Connect your client to React

+## Connect your client to React Connecting Apollo Client to our React app with `react-apollo` allows us to easily bind GraphQL operations to our UI. @@ -130,7 +132,7 @@ Open `src/index.js` and add the following lines of code: _src/index.js_ -```js lines=1,4,6 +```jsx{1,4,6} import { ApolloProvider } from 'react-apollo'; import React from 'react'; import ReactDOM from 'react-dom'; @@ -141,7 +143,8 @@ import Pages from './pages'; ReactDOM.render( - , document.getElementById('root')); + , document.getElementById('root') +); ``` Now, we're ready to start building our first `Query` components in the next section. diff --git a/docs/source/tutorial/data-source.md b/docs/source/tutorial/data-source.md index b21b680..d780694 100644 --- a/docs/source/tutorial/data-source.md +++ b/docs/source/tutorial/data-source.md @@ -11,7 +11,7 @@ Apollo makes connecting these services to your graph simple with our data source In the next sections, we'll build data sources for a REST API and a SQL database and connect them to Apollo Server. Don't worry if you're not familiar with either of those technologies, you won't need to understand them deeply in order to follow the examples. 😀 -

Connect a REST API

+## Connect a REST API First, let's connect the [Space-X v2 REST API](https://github.com/r-spacex/SpaceX-API) to our graph. To get started, install the `apollo-datasource-rest` package: @@ -40,7 +40,7 @@ module.exports = LaunchAPI; The Apollo `RESTDataSource` also sets up an in-memory cache that caches responses from our REST resources with no additional setup. We call this **partial query caching**. What's great about this cache is that you can reuse existing caching logic that your REST API exposes. If you're curious to learn more about partial query caching with Apollo data sources, please check out [our blog post](https://blog.apollographql.com/easy-and-performant-graphql-over-rest-e02796993b2b). -

Write data fetching methods

+### Write data fetching methods The next step is to add methods to the `LaunchAPI` data source that correspond to the queries our graph API needs to fetch. According to our schema, we'll need a method to get all of the launches. Let's add a `getAllLaunches` method to our `LaunchAPI` class now: @@ -118,11 +118,11 @@ The `getLaunchById` method takes in a flight number and returns the data for a p Now that we've connected our REST API successfully, let's connect our database! -

Connect a database

+## Connect a database Our REST API is read-only, so we need to connect our graph API to a database for saving and fetching user data. This tutorial uses SQLite for our SQL database, and Sequelize for our ORM. Our `package.json` already included these packages, thus they were installed in the first part of this tutorial with `npm install`. Also, since this section contains some SQL-specific code that isn't necessary to understanding Apollo data sources, we've already built a `UserAPI` data source for you in `src/datasources/user.js`. Please navigate to that file so we can explain the overall concepts. -

Build a custom data source

+### Build a custom data source Apollo doesn't have support for a SQL data source yet (although we'd love to help guide you if you're interested in contributing), so we will need to create a custom data source for our database by extending the generic Apollo data source class. You can create your own with the `apollo-datasource` package. @@ -140,7 +140,7 @@ Let's go over some of the methods we created in `src/datasources/user.js` to fet - `getLaunchIdsByUser()`: Returns all booked launches for the logged in user - `isBookedOnLaunch({ launchId })`: Determines whether the logged in user booked a certain launch -

Add data sources to Apollo Server

+## Add data sources to Apollo Server Now that we've built our `LaunchAPI` data source to connect our REST API and our `UserAPI` data source to connect our SQL database, we need to add them to our graph API. @@ -148,7 +148,7 @@ Adding our data sources is simple, just create a `dataSources` property on your _src/index.js_ -```js line=3,5,6,8,12-15 +```js{3,5,6,8,12-15} const { ApolloServer } = require('apollo-server'); const typeDefs = require('./schema'); const { createStore } = require('./utils'); diff --git a/docs/source/tutorial/introduction.md b/docs/source/tutorial/introduction.md index 9e5cf28..c806523 100644 --- a/docs/source/tutorial/introduction.md +++ b/docs/source/tutorial/introduction.md @@ -7,7 +7,7 @@ Welcome! We're excited that you've decided to learn Apollo. This fullstack tutor We want you to feel confident that you have the knowledge you need to build a production-ready app with Apollo, so we're forgoing hello world in favor of a real world example complete with authentication, pagination, testing, and more. Ready? Let's dive right in! -

What is Apollo?

+## What is Apollo? Apollo is a complete platform for implementing a graph over your data. It includes two runtime libraries, **Apollo Server** and **Apollo Client**, for building and querying your graph's API. It also features developer tooling that integrates with your existing workflow and gives you full visibility into the performance and security of your graph. @@ -19,7 +19,7 @@ Why do you need a graph? Today, one of the most difficult parts of building an a **[GraphQL](https://www.graphql.org/)** is the specification that we'll be using to communicate between our graph API and client. The spec itself is language-agnostic and unopinionated, so we're choosing to implement GraphQL with the Apollo platform. -

What we'll build

+## What we'll build In this tutorial, we'll build an interactive app for reserving your spot on an upcoming Space-X launch. You can think of it as an Airbnb for space travel! All of the data is real, thanks to the [SpaceX-API](https://github.com/r-spacex/SpaceX-API). @@ -33,11 +33,11 @@ The app has five screens: a login screen, a list of launches, a launch detail, a We want this to model a real world Apollo app as much as possible, so we're covering essential topics like authentication, pagination, state management, testing, and deployment. -

Prerequisites

+## Prerequisites The tutorial assumes that you're comfortable with JavaScript/ES6, you've fetched data from an API before, and you have basic familiarity with React. If you need to brush up on your React skills, we recommend going through the [official tutorial](https://reactjs.org/tutorial/tutorial.html). Building your frontend with React is not a requirement for using Apollo, although it is the most popular way developers integrate with Apollo Client. Even if you use another view layer like Angular or Vue, you will still be able to pick up on the concepts covered in the client section and apply them to your view layer of choice. -

System requirements

+### System requirements Before we begin, make sure you have: @@ -47,7 +47,7 @@ Before we begin, make sure you have: While it's not a requirement, we recommend using [VSCode](https://code.visualstudio.com/) as your editor so you can take advantage of all the awesome features the Apollo VSCode extension enables. We're hoping to support other editors in the future. -

Set up your development environment

+## Set up your development environment Now the fun begins! First, you'll need to install our developer tools: @@ -65,9 +65,9 @@ There are two folders: one for the starting point (`start`) and one for the fina +### Configure Apollo VSCode --> -

Where can I get help?

+### Where can I get help? We know that learning a new technology can sometimes be overwhelming, and it's totally normal to get stuck! If that happens, we recommend joining the [Apollo Spectrum](https://spectrum.chat/apollo) community and posting in the relevant channel (either #apollo-server or #apollo-client) for some quick answers. diff --git a/docs/source/tutorial/local-state.md b/docs/source/tutorial/local-state.md index 39ccd65..218faf9 100644 --- a/docs/source/tutorial/local-state.md +++ b/docs/source/tutorial/local-state.md @@ -11,7 +11,7 @@ We recommend managing local state in the Apollo cache instead of bringing in ano Managing local data with Apollo Client is very similar to how you've already managed remote data in this tutorial. You'll write a client schema and resolvers for your local data. You'll also learn to query it with GraphQL just by specifying the `@client` directive. Let's dive in! -

Write a local schema

+### Write a local schema Just like how a schema is the first step toward defining our data model on the server, writing a local schema is the first step we take on the client. @@ -44,7 +44,7 @@ To build a client schema, we **extend** the types of our server schema and wrap We can also add local fields to server data by extending types from our server. Here, we're adding the `isInCart` local field to the `Launch` type we receive back from our graph API. -

Initialize the store

+## Initialize the store Now that we've created our client schema, let's learn how to initialize the store. Since queries execute as soon as the component mounts, it's important for us to warm the Apollo cache with some default state so those queries don't error out. We will need to write initial data to the cache for both `isLoggedIn` and `cartItems`: @@ -52,7 +52,7 @@ Jump back to `src/index.js` and notice we had already added a `cache.writeData` _src/index.js_ -```js line=1,11-12,15-20 +```js{1,11-12,15-20} import { resolvers, typeDefs } from './resolvers'; const client = new ApolloClient({ @@ -77,7 +77,7 @@ cache.writeData({ Now that we've added default state to the Apollo cache, let's learn how to query local data from within our React components. -

Query local data

+## Query local data Querying local data from the Apollo cache is almost the same as querying remote data from a graph API. The only difference is that you add a `@client` directive to a local field to tell Apollo Client to pull it from the cache. @@ -85,7 +85,7 @@ Let's look at an example where we query the `isLoggedIn` field we wrote to the c _src/index.js_ -```js line=8,17-19 +```jsx{8,17-19} import { Query, ApolloProvider } from 'react-apollo'; import gql from 'graphql-tag'; @@ -135,7 +135,7 @@ Next, we render our `Query` component and bind it to our `GetCartItems` query: _src/pages/cart.js_ -```js +```jsx export default function Cart() { return ( @@ -165,7 +165,7 @@ export default function Cart() { It's important to note that you can mix local queries with remote queries in a single GraphQL document. Now that you're a pro at querying local data with GraphQL, let's learn how to add local fields to server data. -

Adding virtual fields to server data

+### Adding virtual fields to server data One of the unique advantages of managing your local data with Apollo Client is that you can add **virtual fields** to data you receive back from your graph API. These fields only exist on the client and are useful for decorating server data with local state. In our example, we're going to add an `isInCart` virtual field to our `Launch` type. @@ -204,7 +204,7 @@ Now, you're ready to query your virtual field on the launch detail page! Similar _src/pages/launch.js_ -```js line=4 +```js{4} export const GET_LAUNCH_DETAILS = gql` query LaunchDetails($launchId: ID!) { launch(id: $launchId) { @@ -220,17 +220,17 @@ export const GET_LAUNCH_DETAILS = gql` `; ``` -

Update local data

+## Update local data Up until now, we've focused on querying local data from the Apollo cache. Apollo Client also lets you update local data in the cache with either **direct cache writes** or **client resolvers**. Direct writes are typically used to write simple booleans or strings to the cache whereas client resolvers are for more complicated writes such as adding or removing data from a list. -

Direct cache writes

+### Direct cache writes Direct cache writes are convenient when you want to write a simple field, like a boolean or a string, to the Apollo cache. We perform a direct write by calling `client.writeData()` and passing in an object with a data property that corresponds to the data we want to write to the cache. We've already seen an example of a direct write, when we called `client.writeData` in the `onCompleted` handler for the login `Mutation` component. Let's look at a similar example, where we copy the code below to create a logout button: _src/containers/logout-button.js_ -```js line=14 +```jsx import React from 'react'; import styled from 'react-emotion'; import { ApolloConsumer } from 'react-apollo'; @@ -244,7 +244,7 @@ export default function LogoutButton() { {client => ( { - client.writeData({ data: { isLoggedIn: false } }); + client.writeData({ data: { isLoggedIn: false } }); // highlight-line localStorage.clear(); }} > @@ -269,7 +269,7 @@ We can also perform direct writes within the `update` function of a `Mutation` c _src/containers/book-trips.js_ -```js line=30-32 +```jsx{30-32} import React from 'react'; import { Mutation } from 'react-apollo'; import gql from 'graphql-tag'; @@ -319,7 +319,7 @@ export default function BookTrips({ cartItems }) { In this example, we're directly calling `cache.writeData` to reset the state of the `cartItems` after the `BookTrips` mutation is sent to the server. This direct write is performed inside of the update function, which is passed our Apollo Client instance. -

Local resolvers

+### Local resolvers We're not done yet! What if we wanted to perform a more complicated local data update such as adding or removing items from a list? For this situation, we'll use a local resolver. Local resolvers have the same function signature as remote resolvers (`(parent, args, context, info) => data`). The only difference is that the Apollo cache is already added to the context for you. Inside your resolver, you'll use the cache to read and write data. @@ -366,7 +366,7 @@ Now that our local mutation is complete, let's build out the rest of the `Action _src/containers/action-button.js_ -```js +```jsx import React from 'react'; import { Mutation } from 'react-apollo'; import gql from 'graphql-tag'; diff --git a/docs/source/tutorial/mutations.md b/docs/source/tutorial/mutations.md index 63465f3..9b1a7b0 100644 --- a/docs/source/tutorial/mutations.md +++ b/docs/source/tutorial/mutations.md @@ -7,13 +7,13 @@ Time to accomplish: _12 Minutes_ With Apollo Client, updating data from a graph API is as simple as calling a function. Additionally, the Apollo Client cache is smart enough to automatically update in most cases. In this section, we'll learn how to use the `Mutation` component from `react-apollo` to login a user. -

What is a Mutation component?

+## What is a Mutation component? The `Mutation` component is another important building block in an Apollo app. It's a React component that provides a function to execute a GraphQL mutation. Additionally, it tracks the loading, completion, and error state of that mutation. Updating data with a `Mutation` component from `react-apollo` is very similar to fetching data with a `Query` component. The main difference is that the first argument to the `Mutation` render prop function is a **mutate function** that actually triggers the mutation when it is called. The second argument to the `Mutation` render prop function is a result object that contains loading and error state, as well as the return value from the mutation. Let's see an example: -

Update data with Mutation

+## Update data with Mutation The first step is defining our GraphQL mutation. To start, navigate to `src/pages/login.js` and copy the code below so we can start building out the login screen: @@ -37,7 +37,7 @@ Just like before, we're using the `gql` function to wrap our GraphQL mutation so _src/pages/login.js_ -```js +```jsx export default function Login() { return ( @@ -51,7 +51,7 @@ Our `Mutation` component takes a render prop function as a child that exposes a To create a better experience for our users, we want to persist the login between sessions. In order to do that, we need to save our login token to `localStorage`. Let's learn how we can use the `onCompleted` handler on `Mutation` to persist our login: -

Expose Apollo Client with ApolloConsumer

+### Expose Apollo Client with ApolloConsumer One of the main functions of `react-apollo` is that it puts your `ApolloClient` instance on React's context. Sometimes, we need to access the `ApolloClient` instance to directly call a method that isn't exposed by the `react-apollo` helper components. The `ApolloConsumer` component can help us access the client. @@ -61,7 +61,7 @@ In our `onCompleted` handler, we also call `client.writeData` to write local dat _src/pages/login.js_ -```js lines=3,4,7-10,22 +```jsx{3,4,7-10,22} export default function Login() { return ( @@ -88,19 +88,19 @@ export default function Login() { } ``` -

Attach authorization headers to the request

+### Attach authorization headers to the request We're almost done completing our login feature! Before we do, we need to attach our token to the GraphQL request's headers so our server can authorize the user. To do this, navigate to `src/index.js` where we create our `ApolloClient` and replace the code below for the constructor: _src/index.js_ -```js lines=5,6 +```js const client = new ApolloClient({ cache, link: new HttpLink({ uri: 'http://localhost:4000/graphql', - headers: { - authorization: localStorage.getItem('token'), + headers: { // highlight-line + authorization: localStorage.getItem('token'), // highlight-line }, }), }); diff --git a/docs/source/tutorial/production.md b/docs/source/tutorial/production.md index a271d07..27e42a2 100644 --- a/docs/source/tutorial/production.md +++ b/docs/source/tutorial/production.md @@ -9,13 +9,13 @@ Great job for making it this far! We've already learned how to build a GraphQL A An Apollo GraphQL API can be deployed to any cloud service, such as Heroku, AWS Lambda, or Netlify. In this tutorial, we'll deploy our graph API to [Zeit Now](https://zeit.co/now). You will need to create a [Now account](https://zeit.co/signup) in order to follow these steps. If you haven't already created an [Apollo Engine](https://engine.apollographql.com/) account, you will need to sign up for one. -

Publish your schema to Engine

+## Publish your schema to Engine Before we deploy our app, we need to publish our schema to the Apollo Engine cloud service in order to power developer tooling like VSCode and keep track of schema changes. Just like npm is a registry for JavaScript packages, Apollo Engine contains a schema registry that makes it simple to pull the most recent schema from the cloud. In a production application, you should set up this publishing script as part of your CI workflow. For now, we will run a script in our terminal that uses the Apollo CLI to publish our schema to Engine. -

Get an Engine API key

+### Get an Engine API key First, we need an Apollo Engine API key. Navigate to [Apollo Engine](https://engine.apollographql.com/), login, and click on New Service at the top. The prompt will instruct you to name your service. When you're finished, click Create Service. You'll see a key appear prefixed by `service:`. Copy that key so we can save it as an environment variable. @@ -33,7 +33,7 @@ ENGINE_API_KEY=service:my-service-439:E4VSTiXeFWaSSBgFWXOiSA Our key is now stored under the environment variable `ENGINE_API_KEY`. -

Check and publish with the Apollo CLI

+### Check and publish with the Apollo CLI 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: @@ -51,7 +51,7 @@ For subsequent publishes, we may first want to check for any breaking changes in npx apollo service:check --endpoint=http://localhost:4000 ``` -

What are the benefits of Engine?

+### What are the benefits of Engine? Publishing your schema to Apollo Engine unlocks many features necessary for running a graph API in production. Some of these features include: @@ -64,7 +64,7 @@ We also want to be transparent that the features we just described, such as view We're committed to helping you succeed in building and running an Apollo graph API. This is why features such as publishing and downloading schemas from the registry, our open source offerings like Apollo Client and Apollo Server, and certain developer tools like Apollo VSCode and Apollo DevTools will always be free forever. -

Deploy your graph API

+## Deploy your graph API To deploy our app to Now, run the `now` command from the `server` directory of the app. The command may prompt you to login if you haven't already. diff --git a/docs/source/tutorial/queries.md b/docs/source/tutorial/queries.md index c7c4c66..68aa020 100644 --- a/docs/source/tutorial/queries.md +++ b/docs/source/tutorial/queries.md @@ -7,13 +7,13 @@ description: Learn how to fetch data with the Query component Apollo Client simplifies fetching data from a graph API because it intelligently caches your data, as well as tracks loading and error state. In the previous section, we learned how to fetch a sample query with Apollo Client without using a view integration. In this section, we'll learn how to use the `Query` component from `react-apollo` to fetch more complex queries and execute features like pagination. -

The Query component

+## The Query component The `Query` component is one of the most important building blocks of an Apollo app. It's a React component that fetches a GraphQL query and exposes the result so you can render your UI based on the data it returns. The `Query` component uses the **render prop** pattern to fetch and load data from queries into our UI. The render prop pattern provides the ability to add a function as a child to our `Query` component that will notify React about what you want to render. It exposes the `error`, `loading` and `data` on a result object that is passed into the render prop function. Let's see an example: -

Fetching a list

+## Fetching a list To create a `Query` component, import `Query` from `react-apollo`, pass your query wrapped with `gql` to `this.props.query`, and provide a render prop function to `this.props.children` that uses the `loading`, `data`, and `error` properties on the result object to render UI in your app. @@ -56,7 +56,7 @@ Now, let's pass that query to Apollo's `Query` component to render the list: _src/pages/launches.js_ -```js +```jsx export default function Launches() { return ( @@ -87,7 +87,7 @@ To render the list, we pass the `GET_LAUNCHES` query from the previous step into We're not done yet! Right now, this query is only fetching the first 20 launches from the list. To fetch the full list of launches, we need to build a pagination feature that displays a `Load More` button for loading more items on the screen. Let's learn how! -

Build a paginated list

+### Build a paginated list Apollo Client has built-in helpers to make adding pagination to our app much easier than it would be if we were writing the logic ourselves. @@ -95,11 +95,11 @@ To build a paginated list with Apollo, we first need to destructure the `fetchMo _src/pages/launches.js_ -```js lines=4 +```jsx export default function Launches() { return ( - {({ data, loading, error, fetchMore }) => { + {({ data, loading, error, fetchMore }) => { // highlight-line // same as above }} @@ -113,16 +113,16 @@ Copy the code below and add it above the closing `` tag in the render _src/pages/launches.js_ -```js lines=5,9 +```jsx {data.launches && data.launches.hasMore && (