Skip to content

Commit

Permalink
Merge pull request #6537 from apollographql/release-3.9.0
Browse files Browse the repository at this point in the history
Release 3.9.0
  • Loading branch information
trevor-scheer committed Jun 15, 2022
2 parents 5bd3d69 + 36ecbb1 commit 5188b1e
Show file tree
Hide file tree
Showing 119 changed files with 1,596 additions and 2,167 deletions.
3 changes: 0 additions & 3 deletions .codesandbox/ci.json
Expand Up @@ -6,9 +6,6 @@
"packages/apollo-reporting-protobuf",
"packages/apollo-server",
"packages/apollo-server-azure-functions",
"packages/apollo-server-cache-memcached",
"packages/apollo-server-cache-redis",
"packages/apollo-server-caching",
"packages/apollo-server-cloud-functions",
"packages/apollo-server-cloudflare",
"packages/apollo-server-core",
Expand Down
2 changes: 2 additions & 0 deletions .prettierignore
Expand Up @@ -10,3 +10,5 @@ docs/.cache/

# Don't format generated files!
**/generated/**

.volta
12 changes: 11 additions & 1 deletion CHANGELOG.md
Expand Up @@ -7,8 +7,18 @@ The version headers in this history reflect the versions of Apollo Server itself
- [`@apollo/gateway`](https://github.com/apollographql/federation/blob/HEAD/gateway-js/CHANGELOG.md)
- [`@apollo/federation`](https://github.com/apollographql/federation/blob/HEAD/federation-js/CHANGELOG.md)


## vNEXT

- Nothing yet! Stay tuned.

## v3.9.0

- 鈿狅笍 **SECURITY** `apollo-server-core`: The default configuration of Apollo Server is vulnerable to denial of service attacks via memory exhaustion. If you do not currently specify the `cache` option to `new ApolloServer()`, we strongly recommend you specify `cache: 'bounded'`, which replaces the default in-memory unbounded cache with a 30MB in-memory cache, or disable automatic persisted queries with `persistedQueries: null`. Apollo Server now logs a warning in production if you do not configure the cache or disable APQs. See [the docs](https://www.apollographql.com/docs/apollo-server/performance/cache-backends#ensuring-a-bounded-cache) for more details.
- The `apollo-server-caching` package is no longer published. The TypeScript types `KeyValueCache` and `KeyValueCacheSetOptions` and the classes `PrefixingKeyValueCache` and `InMemoryLRUCache` can be imported from `@apollo/utils.keyvaluecache` instead. The first three exports are identical; `InMemoryLRUCache` is based on `lru-cache` v7 instead of v6, and no longer supports creating unbounded caches (which was the default behavior for `apollo-server-caching`'s `InMemoryLRUCache`). [PR #6522](https://github.com/apollographql/apollo-server/pull/6522)
- The `apollo-server-cache-redis` and `apollo-server-cache-memcached` packages are no longer published (though previous versions continue to work). We recommend that users of these packages migrate to `@apollo/utils.keyvadapter`, which lets you connect to Redis, Memcached, or any other backend supported by the [Keyv](https://www.npmjs.com/package/keyv) project. See [the new cache backend docs](https://www.apollographql.com/docs/apollo-server/performance/cache-backends) for more details. [PR #6541](https://github.com/apollographql/apollo-server/pull/6541)
- Avoid unhandled rejection errors if the end hook from a `parsingDidStart` plugin method rejects. [Issue #6567](https://github.com/apollographql/apollo-server/pull/6567) [PR #6559](https://github.com/apollographql/apollo-server/pull/6559)

## v3.8.2

- `apollo-server-core`: Fix usage reporting plugin "willResolveField called after stopTiming!" error caused by a race condition related to null bubbling. [Issue #4472](https://github.com/apollographql/apollo-server/issues/4472) [PR #6398](https://github.com/apollographql/apollo-server/pull/6398)
Expand Down Expand Up @@ -92,7 +102,7 @@ The version headers in this history reflect the versions of Apollo Server itself
new ApolloServer({
documentStore: new InMemoryLRUCache<DocumentNode>({
maxSize: Math.pow(2, 20) * approximateDocumentStoreMiB,
sizeCalculator: InMemoryLRUCache.jsonBytesSizeCalculator,
sizeCalculator: InMemoryLRUCache.sizeCalculator,
}),
...moreOptions,
})
Expand Down
3 changes: 3 additions & 0 deletions cspell-dict.txt
Expand Up @@ -79,6 +79,8 @@ iteratees
josephg
jsdelivr
keyv
keyvadapter
keyvaluecache
KHTML
Kubernetes
linearizability
Expand All @@ -87,6 +89,7 @@ Loftis
loglevel
Luca
MAXAGE
memjs
mget
Mget
microrouter
Expand Down
34 changes: 28 additions & 6 deletions docs/source/api/apollo-server.mdx
Expand Up @@ -20,6 +20,7 @@ const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true, // highly recommended
cache: 'bounded',
});
```

Expand Down Expand Up @@ -202,19 +203,19 @@ A key-value cache that Apollo Server uses to store previously encountered GraphQ

Whenever Apollo Server receives an incoming operation, it checks whether that exact operation is present in its `documentStore`. If it's present, Apollo Server can safely skip parsing and validating the operation, thereby improving performance.

The default `documentStore` is an [`InMemoryLRUCache`](https://github.com/apollographql/apollo-server/blob/main/packages/apollo-server-caching/src/InMemoryLRUCache.ts) with an approximate size of 30MiB. This is usually sufficient unless the server processes a large number of unique operations. Provide this option if you want to change the cache size or store the cache information in an alternate location.
The default `documentStore` is an [`InMemoryLRUCache`](https://github.com/apollographql/apollo-utils/blob/main/packages/keyValueCache/src/InMemoryLRUCache.ts) with an approximate size of 30MiB. This is usually sufficient unless the server processes a large number of unique operations. Provide this option if you want to change the cache size or store the cache information in an alternate location.

To use `InMemoryLRUCache` but change its size to an amount `approximateDocumentStoreMiB`:

<div style="max-width: 400px;">

```typescript
import { InMemoryLRUCache } from 'apollo-server-caching';
import { InMemoryLRUCache } from '@apollo/utils.keyvaluecache';
import type { DocumentNode } from 'graphql';
new ApolloServer({
documentStore: new InMemoryLRUCache<DocumentNode>({
maxSize: Math.pow(2, 20) * approximateDocumentStoreMiB,
sizeCalculator: InMemoryLRUCache.jsonBytesSizeCalculator,
sizeCalculation: InMemoryLRUCache.sizeCalculation,
}),
// ...
})
Expand All @@ -228,6 +229,26 @@ Available in Apollo Server v3.4.0 and later.
</td>
</tr>

<tr>
<td>

##### `cache`

`KeyValueCache | "bounded"`
</td>
<td>

A `KeyValueCache` which Apollo Server uses for several features, including APQs and full response caching. This cache is also available to Apollo Server's data sources and plugins.

By default, the cache that Apollo Server 3 uses is unbounded. We _strongly recommend_ that all users pass `cache: "bounded"` or configure their cache in a manner that isn't unbounded. This protects your server from attacks that exhaust available memory, causing a DOS.

The default bounded cache is an [`InMemoryLRUCache`](https://www.npmjs.com/package/@apollo/utils.keyvaluecache) with a default size of roughly 30MiB.

To learn more about configuring Apollo Server's cache, see [Configuring cache backends](../performance/cache-backends).

</td>
</tr>


<tr>
<td colspan="2">
Expand Down Expand Up @@ -429,7 +450,7 @@ The default value is `true`. Set this to `false` to use mocked resolvers only fo

##### `nodeEnv`

`String`
`string`
</td>
<td>

Expand Down Expand Up @@ -562,7 +583,7 @@ Returns a `Promise` that resolves to an object containing the following properti

##### `url`

`String`
`string`
</td>
<td>

Expand Down Expand Up @@ -726,6 +747,7 @@ async function startApolloServer() {
typeDefs,
resolvers,
csrfPrevention: true,
cache: 'bounded',
plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
});

Expand Down Expand Up @@ -774,7 +796,7 @@ async function startApolloServer() {

##### `path`

`String`
`string`
</td>
<td>

Expand Down
2 changes: 2 additions & 0 deletions docs/source/api/plugin/cache-control.md
Expand Up @@ -21,6 +21,7 @@ const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: "bounded",
plugins: [
ApolloServerPluginCacheControl({
// Cache everything for 1 second by default.
Expand All @@ -42,6 +43,7 @@ const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: "bounded",
plugins: [ApolloServerPluginCacheControlDisabled()],
});
```
Expand Down
1 change: 1 addition & 0 deletions docs/source/api/plugin/drain-http-server.mdx
Expand Up @@ -39,6 +39,7 @@ async function startApolloServer() {
typeDefs,
resolvers,
csrfPrevention: true,
cache: 'bounded',
plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
});

Expand Down
2 changes: 2 additions & 0 deletions docs/source/api/plugin/inline-trace.md
Expand Up @@ -21,6 +21,7 @@ const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: "bounded",
plugins: [
ApolloServerPluginInlineTrace({
rewriteError: (err) => err.message.match(SENSITIVE_REGEX) ? null : err,
Expand All @@ -39,6 +40,7 @@ const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: "bounded",
plugins: [ApolloServerPluginInlineTraceDisabled()],
});
```
Expand Down
10 changes: 7 additions & 3 deletions docs/source/api/plugin/landing-pages.md
Expand Up @@ -29,17 +29,19 @@ To configure these default plugins while still using same `NODE_ENV`-based logic

```js
import { ApolloServer } from "apollo-server";
import { ApolloServerPluginLandingPageLocalDefault,
ApolloServerPluginLandingPageProductionDefault
import {
ApolloServerPluginLandingPageLocalDefault,
ApolloServerPluginLandingPageProductionDefault
} from "apollo-server-core";

const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: "bounded",
plugins: [
// Install a landing page plugin based on NODE_ENV
process.env.NODE_ENV === 'production'
process.env.NODE_ENV === "production"
? ApolloServerPluginLandingPageProductionDefault({
graphRef: "my-graph-id@my-graph-variant",
footer: false,
Expand Down Expand Up @@ -428,6 +430,7 @@ const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: "bounded",
plugins: [
ApolloServerPluginLandingPageGraphQLPlayground(),
],
Expand Down Expand Up @@ -512,6 +515,7 @@ const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: "bounded",
plugins: [
ApolloServerPluginLandingPageDisabled(),
],
Expand Down
1 change: 1 addition & 0 deletions docs/source/api/plugin/schema-reporting.md
Expand Up @@ -23,6 +23,7 @@ const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: "bounded",
plugins: [
ApolloServerPluginSchemaReporting(),
],
Expand Down
2 changes: 2 additions & 0 deletions docs/source/api/plugin/usage-reporting.md
Expand Up @@ -25,6 +25,7 @@ const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: "bounded",
plugins: [
ApolloServerPluginUsageReporting({
fieldLevelInstrumentation: 0.5,
Expand Down Expand Up @@ -454,6 +455,7 @@ const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: "bounded",
plugins: [ApolloServerPluginUsageReportingDisabled()],
});
```
Expand Down
1 change: 1 addition & 0 deletions docs/source/builtin-plugins.md
Expand Up @@ -31,6 +31,7 @@ const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: "bounded",
plugins: [
// Sets a non-default option on the usage reporting plugin
ApolloServerPluginUsageReporting({
Expand Down
1 change: 1 addition & 0 deletions docs/source/config.json
Expand Up @@ -40,6 +40,7 @@
},
"Performance": {
"Caching": "/performance/caching",
"Cache backends": "/performance/cache-backends",
"Automatic persisted queries": "/performance/apq"
},
"Security": {
Expand Down
60 changes: 6 additions & 54 deletions docs/source/data/data-sources.mdx
Expand Up @@ -55,6 +55,7 @@ const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: "bounded",
dataSources: () => {
return {
moviesAPI: new MoviesAPI(),
Expand Down Expand Up @@ -88,66 +89,17 @@ const resolvers = {

## Caching

By default, data source implementations use Apollo Server's [`InMemoryLRUCache`](https://github.com/apollographql/apollo-server/blob/0aa0e4b20ef97576ce92733698a7842b61d8280e/packages/apollo-server-caching/src/InMemoryLRUCache.ts#L14) to store the results of past fetches.
By default, data source implementations use Apollo Server's in-memory cache to store the results of past fetches.

When you initialize Apollo Server, you can provide its constructor a _different_ cache object that implements the [`KeyValueCache` interface](https://github.com/apollographql/apollo-server/blob/0aa0e4b20ef97576ce92733698a7842b61d8280e/packages/apollo-server-caching/src/KeyValueCache.ts#L10-L14). This enables you to back your cache with shared stores like Memcached or Redis.
When you initialize Apollo Server, you can provide its constructor a _different_ cache object that implements the [`KeyValueCache` interface](https://github.com/apollographql/apollo-utils/tree/main/packages/keyValueCache#keyvaluecache-interface). This enables you to back your cache with shared stores like Memcached or Redis.

### Using Memcached/Redis as a cache storage backend
### Using an external cache backend

When running multiple instances of your server, you should use a shared cache backend. This enables one server instance to use the cached result from _another_ instance.

Apollo Server supports using [Memcached](https://memcached.org/) or [Redis](https://redis.io/) as cache stores via the [`apollo-server-cache-memcached`](https://www.npmjs.com/package/apollo-server-cache-memcached) and [`apollo-server-cache-redis`](https://www.npmjs.com/package/apollo-server-cache-redis) packages. You can specify which one to use by creating an instance and passing it into the `ApolloServer` constructor.

#### Memcached

```js
const { MemcachedCache } = require('apollo-server-cache-memcached');

const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: new MemcachedCache(
['memcached-server-1', 'memcached-server-2', 'memcached-server-3'],
{ retries: 10, retry: 10000 }, // Options
),
dataSources: () => ({
moviesAPI: new MoviesAPI(),
}),
});
```

For the options you can pass to the underlying Memcached client, [see the documentation](https://github.com/3rd-Eden/memcached).

#### Redis

```js title="Redis"
const { BaseRedisCache } = require('apollo-server-cache-redis');
const Redis = require('ioredis');

const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: new BaseRedisCache({
client: new Redis({
host: 'redis-server',
}),
}),
dataSources: () => ({
moviesAPI: new MoviesAPI(),
}),
});
```

For the options you can pass to the underlying Redis client, [see the documentation](https://github.com/luin/ioredis).

### Implementing your own cache backend

You can create your own implementation of the [`KeyValueCache` interface](https://github.com/apollographql/apollo-server/blob/0aa0e4b20ef97576ce92733698a7842b61d8280e/packages/apollo-server-caching/src/KeyValueCache.ts#L10-L14) to connect to other caching data stores, or to optimize for your application's query characteristics.

For more information, see the README in for [apollo-server-caching](https://www.npmjs.com/package/apollo-server-caching).
Apollo Server supports using [Memcached](https://memcached.org/), [Redis](https://redis.io/), or other cache backends via the [`keyv`](https://www.npmjs.com/package/keyv) package. For examples, see [Configuring external caching](../performance/cache-backends#configuring-external-caching).

You can also choose to implement your own cache backend. For more information, see [Implementing your own cache backend](../performance/cache-backends#implementing-your-own-cache-backend).

## `RESTDataSource` reference

Expand Down
5 changes: 5 additions & 0 deletions docs/source/data/errors.mdx
Expand Up @@ -343,6 +343,7 @@ const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: "bounded",
formatError: (err) => {
// Don't give the specific errors to the client.
if (err.message.startsWith('Database Error: ')) {
Expand Down Expand Up @@ -398,6 +399,7 @@ const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: "bounded",
plugins: [
ApolloServerPluginUsageReporting({
rewriteError(err) {
Expand Down Expand Up @@ -429,6 +431,7 @@ const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: "bounded",
plugins: [
ApolloServerPluginUsageReporting({
rewriteError(err) {
Expand Down Expand Up @@ -467,6 +470,7 @@ const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: "bounded",
plugins: [
ApolloServerPluginUsageReporting({
rewriteError(err) {
Expand Down Expand Up @@ -512,6 +516,7 @@ const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: 'bounded',
plugins: [setHttpPlugin],
});
```

0 comments on commit 5188b1e

Please sign in to comment.