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

AS3: Disentangle graphql-playground from the core ApolloServer API while still making it easy to use #5159

Closed
glasser opened this issue May 2, 2021 · 0 comments

Comments

@glasser
Copy link
Member

glasser commented May 2, 2021

Right now "playground options" are part of the top-level ApolloServer API, and every integration has a special section calling into the Playground API.

The main theme of AS3 is disentangling this project from third-party projects so that folks who want to use AS without the third-party project can do so easily, and so that folks who want to use AS with the third-party project can upgrade the third-party project on their own timeline rather than ours. So making Playground a little less "core" in AS will help with this. (Additionally, both Playground and GraphiQL are only semi-maintained these days.) I have an idea in mind for a very simple bare-bones "serve static UI" addition to the Plugin API that would allow Playground to be a plugin (still just one line of code to turn on). Whether Playground should be the default or not is TBD.

glasser added a commit that referenced this issue May 25, 2021
Apollo Server has graphql-playground built in, to the degree that the
playground-html renderPlaygroundPage options are a top-level key in Apollo
Server config.

This has been very useful, but the theme of Apollo Server 3 is to keep its API
lean and disentangled from other packages. Every single Apollo Server
integration package has the same copy-and-paste code that threads playground
options directly into the playground package.

Additionally, graphql-playground has is retiring (see
graphql/graphql-playground#1143) and merging back into
GraphiQL. So it especially doesn't make sense for Apollo Server's API to
continue to be defined by Playground.

We could just switch back to GraphiQL like in Apollo Server 1, but instead,
let's move UI configuration out of the top-level ApolloServer API and move it
into our plugin system. And let's make sure that the per-web-framework
integration packages don't need to care what UI system you're using.

This PR adds a very very very simple static HTML serving API to our plugin
system. The point of this system is to support plugins that serve a bit of HTML
to load a full UI from CDN, like for Playground, GraphiQL, Explorer, etc, or to
serve a splash page linking to other UIs.

The point of this system is not to be a convenient way to add app-specific HTML
to your app. If you want to do that, just use middleware in your web framework!
The point is to make UI plugins that work out of the box with every Apollo
Server integration. Because of that, the plugins can do very little: they can
serve a single static HTML page. That's it! And you can only install one in your
app.

We add ApolloServerPluginUIGraphQLPlayground in core, as well as
ApolloServerPluginUIDisabled. Like other plugins, if you don't set some UI
plugin of your own and don't set the disabled plugin, Apollo Server will
auto-install a plugin. In this case it installs the playground plugin though we
may change that before 3.0.0.

(The mechanism for implicitly installing ApolloServerPluginUIGraphQLPlayground
is a bit more complex than for our other built-in plugins because we want user
plugins to be able to override the UI, not just other built-in plugins. So
ApolloServerPluginUIDisabled prevents ApolloServerPluginUIGraphQLPlayground from
being installed at all, but other plugins defining renderUIPage get installed
alongside ApolloServerPluginUIGraphQLPlayground and there's logic to make sure
they take precedence.)

We remove the `playground` constructor option (you can pass configuration
options to ApolloServerPluginUIGraphQLPlayground instead), as well as three
playground-related symbols exported from all the main packages.

While we're at it, we simplify how we set up the Playground HTML:
- There was some confusing logic in playground.ts where
  `defaultPlaygroundOptions.settings` listed some setting overrides... which
  were not actually used by default... only if you specified something like
  `playground: {settings: {}}`! We remove these and let the default settings in
  `@apollographql/graphql-playground-react` be the defaults *always* instead of
  *most of the time*.
- Instead of trying to figure out the path to the GraphQL endpoint via a variety
  of different mechanisms (including "in the docs, tell you to edit the source
  to specify `endpoint` yourself), just leave `endpoint` empty by default. This
  makes the React app choose `location.href` for the endpoint, which should be
  fine! (Upgrade `@apollographql/graphql-playground-html` to not log a warning
  when `endpoint` isn't provided, and upgrade
  `@apollographql/graphql-playground-react` to preserve `code` query parameters
  on the endpoint so that the Azure Functions docs work automatically.)

Also:

- Tests that set environment variables (as some of the playground ones do) make
  me uncomfortable. Added `__testing__nodeEnv` to the ApolloServer and
  GraphQLOptions interfaces that can be used to test how `process.env.NODE_ENV`
  affects AS without actually changing the environment.
- Inline fastifyApollo into fastify's ApolloServer.
- I ended up rewriting a bunch of tests that used `request` to use `supertest`
  instead (though for some reason we access it via the symbol `request`). Many
  of these tests had been copied and pasted between packages but I did not
  consolidate them.

Fixes #5159.
glasser added a commit that referenced this issue May 25, 2021
…5206)

Apollo Server has graphql-playground built in, to the degree that the
playground-html renderPlaygroundPage options are a top-level key in Apollo
Server config.

This has been very useful, but the theme of Apollo Server 3 is to keep its API
lean and disentangled from other packages. Every single Apollo Server
integration package has the same copy-and-paste code that threads playground
options directly into the playground package.

Additionally, graphql-playground has is retiring (see
graphql/graphql-playground#1143) and merging back into
GraphiQL. So it especially doesn't make sense for Apollo Server's API to
continue to be defined by Playground.

We could just switch back to GraphiQL like in Apollo Server 1, but instead,
let's move frontend configuration out of the top-level ApolloServer API and move it
into our plugin system. And let's make sure that the per-web-framework
integration packages don't need to care what frontend you're using.

This PR adds a very very very simple static HTML serving API to our plugin
system. The point of this system is to support plugins that serve a bit of HTML
to load a full frontend from CDN, like for Playground, GraphiQL, Explorer, etc, or to
serve a splash page linking to other UIs.

The point of this system is not to be a convenient way to add app-specific HTML
to your app. If you want to do that, just use middleware in your web framework!
The point is to make frontend plugins that work out of the box with every Apollo
Server integration. Because of that, the plugins can do very little: they can
serve a single static HTML page. That's it! And you can only install one in your
app.

We add ApolloServerPluginFrontendGraphQLPlayground in core, as well as
ApolloServerPluginFrontendDisabled. Like other plugins, if you don't set some frontend
plugin of your own and don't set the disabled plugin, Apollo Server will
auto-install a plugin. In this case it installs the playground plugin though we
may change that before 3.0.0.

(The mechanism for implicitly installing ApolloServerPluginFrontendGraphQLPlayground
is a bit more complex than for our other built-in plugins because we want user
plugins to be able to override the UI, not just other built-in plugins. So
ApolloServerPluginFrontendDisabled prevents ApolloServerPluginFrontendGraphQLPlayground from
being installed at all, but other plugins defining renderFrontend get installed
alongside ApolloServerPluginFrontendGraphQLPlayground and there's logic to make sure
they take precedence.)

We remove the `playground` constructor option (you can pass configuration
options to ApolloServerPluginUIGraphQLPlayground instead), as well as three
playground-related symbols exported from all the main packages.

While we're at it, we simplify how we set up the Playground HTML:
- There was some confusing logic in playground.ts where
  `defaultPlaygroundOptions.settings` listed some setting overrides... which
  were not actually used by default... only if you specified something like
  `playground: {settings: {}}`! We remove these and let the default settings in
  `@apollographql/graphql-playground-react` be the defaults *always* instead of
  *most of the time*.
- Instead of trying to figure out the path to the GraphQL endpoint via a variety
  of different mechanisms (including "in the docs, tell you to edit the source
  to specify `endpoint` yourself), just leave `endpoint` empty by default. This
  makes the React app choose `location.href` for the endpoint, which should be
  fine! (Upgrade `@apollographql/graphql-playground-html` to not log a warning
  when `endpoint` isn't provided, and upgrade
  `@apollographql/graphql-playground-react` to preserve `code` query parameters
  on the endpoint so that the Azure Functions docs work automatically.)

Also:

- Tests that set environment variables (as some of the playground ones do) make
  me uncomfortable. Added `__testing__nodeEnv` to the ApolloServer and
  GraphQLOptions interfaces that can be used to test how `process.env.NODE_ENV`
  affects AS without actually changing the environment.
- Inline fastifyApollo into fastify's ApolloServer.
- I ended up rewriting a bunch of tests that used `request` to use `supertest`
  instead (though for some reason we access it via the symbol `request`). Many
  of these tests had been copied and pasted between packages but I did not
  consolidate them.

Fixes #5159.
@glasser glasser closed this as completed May 25, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 20, 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

No branches or pull requests

1 participant