Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 3.0 #5262

Merged
merged 437 commits into from
Jul 12, 2021
Merged

Release 3.0 #5262

merged 437 commits into from
Jul 12, 2021

Conversation

glasser
Copy link
Member

@glasser glasser commented Jun 1, 2021

As with release PRs in the past, this is a PR tracking a release-3.0 branch for an upcoming release of Apollo Server. 🙌

The progress of this release is being tracked in the Apollo Server 3 project, as well as on this issue.

We have released Apollo Server 3.0.0! It is currently on the next npm dist-tag rather than the latest dist-tag, so it is not installed by default when you run npm install apollo-server. We intended to promote it to latest in mid-July pending further feedback.

The current version is 3.0.0. You can install it with npm install [email protected].

When this version is officially released onto the latest npm tag, this PR will be merged into main.

This is the release branch for Apollo Server 3, a major version release! The theme of this release is making Apollo Server more maintainable and replacing hard-coded external dependencies with the ability for users to install their chosen version of the formerly baked-in dependency. There are many backwards-incompatible changes, including whole features that have been removed.

The CHANGELOG is up to date, and there is now a migration guide available. All Apollo Server docs should now be up to date for AS3; AS3 docs are available at https://www.apollographql.com/docs/apollo-server/v3/

While AS3 is mostly about removing complexity and setting the stage for future exciting features, it also has a few new features and capabilities:

  • Now that we target Node 12 and up, we can build for the more efficient ES2020 compilation target.
  • apollo-server-lambda is now built on top of apollo-server-express and optionally supports Express middleware
  • apollo-server-fastify is now compatible with Fastify v3 (instead of Fastify v2)
  • Apollo Server 1 had GraphiQL built in as a frontend; Apollo Server 2 had GraphQL Playground. In Apollo Server 3, there's a simple framework-agnostic plugin interface to let you swap in different frontends with one line of code. (Currently Playground is still the default frontend though this may change before 3.0.0.)

glasser and others added 30 commits May 3, 2021 22:39
We had not previously done this because it drops support for Node v8.

Bump orb to a new version that waits for Verdaccio to start before moving on;
this PR seems to make lerna fast enough that it beats Verdaccio now!

Part of #5119.
Upgrading to TS 4 is generally useful, but it also lets use combine `composite`
with `noEmit`, which lets us actually use `tsconfig.test.json`.

This PR copies a few things we've done recently in the Federation repo.

- Upgrade TypeScript, Jest, and Codecov.
- Drop jest-cucumber dep (hasn't been used for a while).
- Update VSCode task to use the "typescript" type.
- Set enablePromptUseWorkspaceTsdk like in
  apollographql/federation#728
- Stop using moduleNameMapper in jest config, which seemed to create weird
  issues. Instead, just make sure that `npm run compile` happens before you
  run tests (at least when run via `npm test`) via a `pretest` script.
- Fix a lot of compilation errors (mostly caused by actually typechecking tests,
  though some from the upgrade). Most of this is pretty localized, but some
  required more work (eg, replacing a `Map` that was being treated as a
  `KeyValueCache` with an actual `KeyValueCache` implementation).
- I found the moduleNameMapper pulling in a top-level `__mocks__` to be
  confusing and also led to errors about trying to import files from outside a
  project. In fact in general I found `__mocks__` to be confusing. So:
  - I replaced our use of a custom `Date` mocker plus `jest.useFakeTimers` with
    `@sinonjs/fake-timers` (which does both and is what jest's is built on)
  - Replaced `__mocks__/apollo-server-env.ts` with a file that doesn't have
    a special `__mocks__` name
  - Did the same for the ioredis mock, and loaded it into `jest.mock` explicitly
    rather than implicitly
- The thing where we imported a function that defined a jest test suite from the
  `__tests__` of `apollo-server-caching` was sort of weird already, and
  importing from a project that used `noEmit` didn't seem to work at all
  here. So I changed the testing function to just be a normal non-Jest-specific
  function exported from `apollo-server-caching` that can be used in Jest tests
  (or non-Jest tests for that matter) with a bit of preamble. (I changed its
  name too so it's obviously a different function.) Because closing the cache is
  now not part of the test, we didn't need `TestableKeyValueCache` any more so I
  dropped it.
- isDirectiveDefined isn't exported and is now always called with an array, so
  remove code that runs if it doesn't get one and tests that that code works.
- RESTDataSource used to document and test that you can override `baseURL` in a
  subclass with a getter. This is illegal in TS4 so we don't officially support
  it any more.

Additionally, this PR removes global types from `apollo-server-env` (the
`global.d.ts` file). Thanks to @martijnwalraven for figuring this out and
writing the following:

We use exports from `apollo-server-env` to access the Fetch API to avoid
depending on running in specific environments. While environments like
Cloudflare Workers and Deno expose a Fetch API globally, in Node environments
you'd generally like to avoid polyfilling the global context. There are also
differences between the APIs available in these environments that we may want to
account for with our own types.

Unfortunately,`apollo-fetch` uses `cross-fetch` as a global polyfill (see
https://github.com/apollographql/apollo-fetch/blob/0a0b8df241960dfa72abf3bd179e9d936265a7da/packages/apollo-fetch/src/apollo-fetch.ts#L17),
and expects having Fetch API types defined globally.

Because we use `apollo-fetch` in our tests, we've long used a `global.d.ts` in
`apollo-server-env` to make the exported types available globally without
depending on the `dom` lib types (because most of the types in there don't
really make sense in non-browser environments and can lead to accidental usage).

As it turns out however, we also use `superagent` in our tests, and
`@types/superagent` now specifies an explicit dependency on `dom` lib. As
TypeScript makes any global type declarations available throughout a project,
that means our tests now get the `dom` lib types merged into their environment,
resulting in conflicts with the types in `apollo-server-env`'s `global.d.ts`.

Forcing anyone depending on packages like `@types/superagent` to have their
environment extended with the `dom` lib types isn't great, and there are
existing discussions about the implications of this for that package
specifically (see DefinitelyTyped/DefinitelyTyped#41425). There is also a
promising proposal for a `strictEnvironment` option in TypeScript that would
help avoid these situations (see
https://gist.github.com/RyanCavanaugh/702ebd1ca2fc060e58e634b4e30c1c1c).

For now, I've solved this by reluctantly adding `dom` to
`tsconfig.test.base.json`. We should be able to remove this when our
dependencies get fixed or if `strictEnvironment` gets implemented.

I also fixed some typing issues that ironically illustrate the danger of having
these `dom` types available. Because the mocked version of `apollo-server-env`
exported classes through a `const` declaration, that didn't actually export them
as types, just as values (see microsoft/TypeScript#36348). But because we have
similarly named types defined in `dom`, those were used instead. Using named
exports in the `apollo-server-env` mock avoids this.

Fixes #5119.
Changing to an async function seemed like the easiest approach here.
`this.playgroundVersion` doesn't really seem to be a thing, so that line was
just extraneous.
The field types are copied from GraphQLError and Error.
Normally I'd be a bit wary of adding a bunch of `!` to non-test code,
but it's no worse than the status quo with strictNullChecks false.
Technically this is not a no-op if you have `this.requestOptions.parseOptions`,
but the parseOptions line wasn't there at all when this workaround was
originally added in #1126

(I don't remember exactly what was going on here but I assume it was "doesn't
compile without these extra lines".)
Remove most exceptions to TS strict rules
The simplest way to implement this was to inline graphqlKoa (only
exported in Apollo Server 1) into ApolloServer, and change the main
middleware to be explicitly `async` instead of "sometimes `return;` and
sometimes return a Promise".

There's a slight change to error handling in that the newly introduced
`catch` clause also catches anything thrown by the couple of lines after
`runHttpQuery` that processes its output, but that's probably a good
change.

Part of #5170.
As in #5177, the easiest way is to inline hapiApollo (AS1 API) into
ApolloServer.ts.

Also remove some unnecessary `await`s.

Fixes #5170.
Our tests use the deprecated `apollo-fetch` package. This depends on an old
version of the `cross-fetch` polyfill package which itself depends on a version
of `node-fetch` with a minor CVE. This makes `npm audit` noisy, which is sad.

There's no real vulnerability from `node-fetch` here since it's only used in
tests, but it would be nice to quiet `npm audit`. Plus, in #5165 we grudgingly
added `"dom"` to the `lib` in `tsconfig.test.base.json` just to support
`apollo-fetch`.

Updating `cross-fetch` in `apollo-fetch` is not enticing because it does pull in
major version bumps of dependent packages; I wouldn't want to release a new
version of a dead project that makes bad changes in some obscure contexts.

But `apollo-fetch` is a pretty simple package. So instead, I just inlined
`apollo-fetch` into `apollo-server-integration-testsuite`, deleted a bunch of
features we aren't using like batch support, and made it use the
`apollo-server-env` `fetch` rather than a global polyfill.

The only use of `apollo-fetch` that didn't already depend on
`apollo-server-integration-testsuite` was `apollo-server`, so add that
devDependency.

Fixes #5161.
…on (#5182)

In Apollo Server 2, ApolloServer *sometimes* adds the definition of
`@cacheControl` to your schema.

Specifically, it adds it whenever you rely on the implicit call to
`graphql-tools`' `makeExecutableSchema` (ie, you pass `typeDefs` and
`resolvers`). It doesn't add it when you pass your own `schema`, and
oddly it doesn't add it when you use `modules`.

On the other hand, it doesn't care if you actually have cache control
enabled in your app.

What this means is that switching between the implicit call to the
built-in version of `makeExecutableSchema` and using your own copy of
`graphql-tools` has a surprising impact on your schema. We'd like to
make the implicit call just a shorthand and encourage folks who want to
use all of the different options of `makeExecutableSchema` to call it
directly in their app (rather than having tons of pass-through
arguments), so we don't want the semantics to differ in a surprising and
undocumented way.

Plus, other tools that look at your schema will work better if you
define the `@cacheControl` directive explicitly.

AS2 did allow you to define the directive yourself (it only adds it if
it isn't there).

So this PR changes `apollo-server-core` to no longer auto-include the
definitions, and documents how to write them yourself.

(In the future, we may want to change `@cacheControl` to be a Core
Schema feature, but we're not doing that today.)

(AS2 had a similar issue with the types related to `graphql-upload` but
that integration is removed.)

Fixes #5181.
Connect is a pretty old JS web framework; most users (other than Meteor) moved
to Express many years ago.

This PR stops advertising apollo-server-express supports Connect.  It doesn't
actively remove the lines in apollo-server-express which exist for Connect
compatibility and it does continue to test against Connect. However, it does
state that we may choose to remove that compatibility within Apollo Server 3.

Fixes #5172.
…5183)

Note that a previous commit on `release-3.0` stopped exporting all
`graphql-tools` exports from our packages, but the docs had not yet been
updated.

- Update from `graphql-tools@4` to the newest version of various
  `@graphql-tools/X` packages.
- Make it clear that the use of `graphql-tools` functionality in Apollo
  Server is essentially a convenience for the most common use cases, and
  that folks who want to use detailed `graphql-tools` functionality are
  welcome to do so directly.
- Remove support for `schemaDirectives`. This `makeExecutableSchema`
  option is considered to be legacy by `graphql-tools` these days, so
  this seems like a reasonable time to drop it from the Apollo Server
  API. Folks who want to keep using it can use `makeExecutableSchema`
  from `@graphql-tools/schema` directly, or ideally switch to the newer
  `schemaTransforms`. Stop documenting it.
- Remove most docs that just duplicate `graphql-tools` docs. (Keep some
  of the mocking docs.)
- Update mocking support to use `addMocksToSchema` from
  `@graphql-tools/mock` rather than `addMockFunctionsToSchema` from
  `graphql-tools`. Note that this has some backwards-incompatible
  changes, mentioned in the CHANGELOG. Update docs to not claim you can
  look at arguments in mock functions (that's one of those changes).
  Document alternative to deprecated `MockList` class. Remove skipped
  test because presumably the "bug" is by this point expected behavior.
- Only apply mocks to schema in the non-`gateway` codepath rather than
  to schemas provided by the gateway (at startup or later via
  `onSchemaChange`). Assuming your `gateway` is an `ApolloGateway`, this
  should be a no-op as `ApolloGateway` provides an `executor` which
  never calls resolvers on the schema. If you have implemented your own
  `gateway` which does not have an executor that entirely ignores
  resolvers, you can always add mocks to the schema returned from `load`
  and sent to `onSchemaChange` yourself.

Inspired by #4237 by @yaacovCR. Fixes #4923.
…5184)

These were the old AS1 APIs which have not been exported since AS1. Note
that graphqlConnect was already dead code.
…5186)

- Everything in `src/plugins/index.ts` is intended for export from the
  package, but the `export *` line was missed during a merge.
- The instructions in that file tell you not to import directly from
  anything nested under it, so move `internalPlugin.ts` up a level to
  avoid breaking that rule.
- In some tests, import plugin symbols from `apollo-server-core` rather
  than a `dist` directory (VSCode must have added the `dist` imports
  because of the missing `export *`).
…#5188)

Lambda has two ways of defining a handler: as an async Promise-returning
function, and as a callback-invoking function.
https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html

Until v2.21.2 our handler was only a callback-invoking function.
Starting to that version, it could be called in either way. This meant
that the TypeScript types for our handler were somewhat vague (see
#5072).

All current Node Lambda runtimes support calling async functions; the
only reason that we didn't just change directly from callback-invoking
to async in v2.21.2 was to support the use case of user code that wraps
our handler in their own function. But now we're doing AS3 so we can
make backwards-incompatible changes, so if you're doing that, you should
just make your handler async too and `await` the result of our handler.

Fixes #5018.
This branch previously had most references to `engine` options and
`ENGINE_SCHEMA_TAG` removed  but the merge from v2.18 restored some of
them.

Fixes #5191.
This option/package enabled a format for execution traces that was
primarily used for engineproxy (replaced 3 years ago) as well as some
versions of Playground. This `tracing` response extension was very
verbose as it used a flat list for resolvers rather than a nested one
like the `ftv1` extension used by ApolloServerPluginInlineTrace. It is
essentially an attractive nuisance: an innocuously named option that
increases the size of your responses without powering any actively
maintained tools.

We have not yet made any backwards-incompatible changes in the AS plugin
API, so you still can use the AS2 `apollo-server-tracing` plugin
directly with AS3 servers; we just won't publish the package any more
and we won't provide a boolean that installs it for you.

Part of #5158.
This response extension was only read by `engineproxy` which has been
deprecated since 2018. Remove the code that writes it and the
`stripFormattedExtensions` option to control it.

That said, it is nice to be able to have access to the full list of
cache hints (not just the overall policy). (For example, for our tests!)
Previously this was *only* available once the request was done in the
extension in the response. This PR moves the previously-internal hints
map to requestContext, right next to overallCachePolicy.

(This also means that if you really want the `cacheControl` extension,
it's easy to write your own plugin that runs after the cache control
plugin, reads the cacheHints map from RequestContext, and writes the
extension!)

It changes the map to be keyed by string rather than ResponsePath. Map
keys are compared with `===` so ResponsePath isn't a great key choice,
because different copies of identical paths may not be referentially
equal. (It worked before because the only access to the hints Map was
hidden inside the extension and always used a consistent value for any
given path.)

Remove some less relevant integration tests, and change some to look for
the cache-control header instead of the extension.
That means:
- Remove standalone `apollo-cache-control` package. Move the code into
  `apollo-server-core/src/plugin` and some of the types into
  `apollo-server-types`. Make its extensions to `GraphQLRequestContext`
  just be part of the definition of that type.
- Drop top-level `cacheControl` constructor option; instead, use our
  now-standard pattern of "you can put the extension in `plugins`
  yourself, you can put the 'Disabled' version in `plugins`, or
  otherwise AS will add the plugin with default configuration".

There's no "semantic" change in this PR: it just changes how you write
`cacheControl: false` and `cacheControl: options` to
    plugins: [ApolloServerPluginCacheControlDisabled()]
and
    plugins: [ApolloServerPluginCacheControl(options)]
respectively.

When I wrote this commit, I started to get concerned about the ordering
of the cache control plugin (which used to be always first... well,
other than an implicit usage reporting plugin, which adds itself with
this.plugin.unshift) with respect to other plugins like usage reporting
and the response cache plugin. What if it wrote to
requestContext.overallCachePolicy too late? In practice, the ordering
doesn't appear to matter, but see a later commit in this PR for a change
that makes this issue moot by continuously updating overallCachePolicy.
I got stressed out about whether it mattered that the cache control
plugin used to be almost always first in the plugins list. But why does
this matter? It matters because the plugin only updated
overallCachePolicy at a few specific moments in the request pipeline.

This commit simplifies the model by updating
requestPolicy.overallCachePolicy each time a field finishes resolving.

In order to keep the existing unit tests of "addHint" working, I moved
"addHint" to a PolicyUpdater object. Note that there's one extra boolean
of state to track: there's a difference between
"`requestContext.overallCachePolicy` is undefined because we've just
started" (in which case the first hint should override the lack of a
policy) and "`requestContext.overallCachePolicy` is undefined because
we've actually seen something that says the response can't be cached",
in which case we should never change overallCachePolicy. That state gets
tracked inside PolicyUpdater.

I respected the existing logic that never touches overallCachePolicy if
it is set by something outside of the cache control plugin. That said,
the only use case I know of for that is the response cache's
responseForObject, and when it sets overallCachePolicy the query doesn't
get executed and the cache control plugin never tries to write to
overallCachePolicy anyway. So it's not clear how important that logic
is.

Note that we're now careful to call `addHint` only once per field (when
it's done resolving), even with `setCacheHint`. That's because if you
call `info.cacheControl.setCacheHint({maxAge: 10})` on a field with
`@cacheControl(maxAge: 5)`, the 10 does override the 5 and so we can't
have already incorporated the 5 into overallCachePolicy.
This was added in v2.24 without a test.
An earlier commit in this PR replaced the `cacheControl` GraphQL
response exception with a `Map` on `GraphQLRequestContext`. But then a
later commit changed the logic so that the map was *only* being used for
output on the context rather than also as an important bit of
intermediate state.

This map has an entry for at least every object and interface and root
field in the response, and it does a string join for each key in the
map. This is a lot of overhead for just "well maybe some other plugin
might want to read the detailed cache hints". Neither the full response
cache nor the cache header logic needs this.

We can reintroduce this map later if anybody has a use case for it (eg,
a partial response cache) but for now let's be lean and leave it out.
(For the sake of preserving existing helpful tests, we allow tests to
provide a map that will be written to.)
@glasser
Copy link
Member Author

glasser commented Jul 7, 2021

I'm planning to release Apollo Server 3.0.0 to the next dist-tag (so it won't yet be installed by default with npm install apollo-server) in an hour or two.

While we don't foresee needing to take advantage of this, it's possible we may make minorly backwards-incompatible changes to new functionality between the release of 3.0.0 and the promotion to latest.

@glasser
Copy link
Member Author

glasser commented Jul 7, 2021

We've released version 3.0.0, on the next dist-tag! Install it with npm install [email protected]. This PR will remain open for 1-3 weeks until we move AS3 to the latest dist-tag and merge release-3.0 into main.

Docs are available at
https://www.apollographql.com/docs/apollo-server/v3/
including a complete migration guide
https://www.apollographql.com/docs/apollo-server/v3/migration/

glasser and others added 10 commits July 7, 2021 13:45
* Other things that may be worth fixing, marked with FIXME

These are not AS3 regressions.

* Datasources

* Fix field 'bottom-out' condition w/an example

* Address remaining fixmes in resolvers.mdx

* Edits to unions/interfaces article

* Modernize onHealthCheck example

* Resolve FIXMEs in custom scalars article

* Missed deleting fixmes when cherry picking unions-interfaces from another branch

* Address federation + @CacheControl

* Update deprecated docs

* Resolve a chunk of FIXMEs in schema.md

* Fix a broken link I think

* Knock out remaining FIXMEs

* Last bit of feedback from @glasser

Co-authored-by: Trevor Scheer <[email protected]>
Co-authored-by: Stephen Barlow <[email protected]>
@glasser glasser merged commit 291c17e into main Jul 12, 2021
@glasser
Copy link
Member Author

glasser commented Jul 12, 2021

Apollo Server 3.0.0 has now been released and is available on the latest dist-tag! The docs site has been updated to show v2 as an old version and v3 as the current version. Thanks to everyone who has contributed!

@jwoo92
Copy link

jwoo92 commented Jul 12, 2021

@glasser Thank you for the awesome birthday present 😃

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 21, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants