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

Generalize Playground support to a simple "frontend page" plugin API #5206

Merged
merged 11 commits into from
May 25, 2021
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ The version headers in this history reflect the versions of Apollo Server itself

- We no longer re-export the entirety of `graphql-tools` (including `makeExecutableSchema`) from all Apollo Server packages. If you'd like to continue using them, install [`graphql-tools`](https://www.graphql-tools.com/) or one of its sub-packages yourself.
- The `Upload` scalar is no longer exported. (See above as to why.)
- Support for serving an HTML UI has been generalized. While servers in dev mode still default to serving GraphQL Playground (note: this may change before v3.0.0), plugins can define a new `renderUIPage` event which returns an HTML page that is served to browsers. The `playground` option to `new ApolloServer` has been removed; customizing Playground or making it run in production mode can be done by installing the new `ApolloServerPluginUIGraphQLPlayground` plugin yourself. To disable Playground, either install the new `ApolloServerPluginUIDisabled` plugin or install any other plugin that implements `renderUIPage`. Packages no longer export `defaultPlaygroundOptions`, `PlaygroundConfig`, and `PlaygroundRenderPageOptions`. By default, no GraphQL Playground settings are overridden, including the endpoint, which now just defaults to `window.location.href` (with most query parameters removed); this means you typically don't have to manually configure the endpoint.

## v2.24.0

Expand Down
20 changes: 1 addition & 19 deletions docs/source/api/apollo-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -359,24 +359,6 @@ The default value is `10_000` (10 seconds).
</td>
</tr>

<tr>
<td>

###### `playground`

`Boolean` or `Object`
</td>
<td>

If truthy, the server hosts [GraphQL Playground](../testing/graphql-playground) from its URL. Can be an object to pass [configuration options](https://github.com/prismagraphql/graphql-playground/#usage) to the playground.

The default value is `true`, **unless** the `NODE_ENV` environment variable is set to `production`.

Note that [`introspection`](#introspection) must be enabled for GraphQL Playground to function properly.
</td>
</tr>


<tr>
<td>

Expand Down Expand Up @@ -784,7 +766,7 @@ The default value is `true`.

#### `getMiddleware`

Returns an array of the middlewares that together form a complete instance of Apollo Server. Includes middleware for HTTP body parsing, GraphQL Playground, file uploads, and subscriptions.
Returns an array of the middlewares that together form a complete instance of Apollo Server. Includes middleware for HTTP body parsing, health checks, setting CORS headers, and serving a static UI, as well as actually executing GraphQL operations.

Unlike [`applyMiddleware`](#applymiddleware), `getMiddleware` does _not_ automatically apply Apollo Server middlewares to your application. Instead, this method enables you to apply or omit individual middlewares according to your use case. For an Express or Koa application, you can apply a particular middleware by calling `app.use`.

Expand Down
26 changes: 6 additions & 20 deletions docs/source/deployment/azure-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,35 +155,35 @@ Before deploying, a new application must be setup. To do this, we need to create
az group create --name apollo-examples --location eastus
```

After creating a resource group, we need to create a storage account to store our code on Azure.
After creating a resource group, we need to create a storage account to store our code on Azure. You will need to choose a unique name.

```shell
az storage account create \
--name apolloexample \
--name apolloexampleYOURNAME \
--location eastus \
--resource-group apollo-examples \
--sku Standard_LRS
```

We will publish our application to Azure now using the CLI as well. We need to create a `functionapp` running the following command.

Note: The your function name must be unique.
Note: The function name must be unique.

```shell
az functionapp create \
--resource-group apollo-examples \
--name apollo-example \
--name apollo-example-YOURNAME \
--consumption-plan-location eastus \
--runtime node \
--storage-account apolloexample
--storage-account apolloexampleYOURNAME
```

### Publishing our project to the function app

After creating a functionapp, it is just to publish our function to azure. The command below could be used to perform releases to all of your functions.

```shell
func azure functionapp publish apollo-example
func azure functionapp publish apollo-example-YOURNAME
```

```shell
Expand All @@ -200,14 +200,6 @@ Functions in apollo-example:

Finally, going to the Invoke URL shown at the output above, we will see our result.

Note: When GraphQL Playground starts, It won't have the correct URL containing the security `code`, and a message **"Server cannot be reached"** as shown at your browser.

![Apollo server running on azure with error](../images/deployment/azure-functions/apollo-server-on-azure.png)

We just need to put the full URL that includes the security `code` in the Playground url box. The background polling should refresh the screen momentarily. Click the **Schema** button to see if the docs are loaded correctly as shown in the image below.

![Apollo server running on azure with success](../images/deployment/azure-functions/apollo-server-on-azure-sucess.png)

### Cleaning Up

After completing this tutorial, you can delete all the resources you created during this example from your Azure account by removing the Azure Resource Group called **apollo-examples** with the **az group** commmand. We can manually delete each resource using the following commands:
Expand All @@ -233,12 +225,6 @@ It is also possible to publish your project from VS Code using the Azure Functio

Once deployment is complete, view the output in VS Code and you should be able to see the url of your GraphQL endpoint. It will look something like **https://our-graphql-project.azurewebsites.net/api/graphql**. Navigate to the url and you should find GraphQL Playground.

Note: When GraphQL Playground starts, It won't have the correct URL containing the security `code`, and a message **"Server cannot be reached"** as shown at your browser.

![Apollo server running on azure with error](../images/deployment/azure-functions/apollo-server-on-azure.png)

We just need to put the full URL that includes the security `code` in the Playground url box. The background polling should refresh the screen momentarily. Click the **Schema** button to see if the docs are loaded correctly as the image below.

Need more details? See the [Docs](https://www.npmjs.com/package/apollo-server-azure-functions)
at the NPM repository.

Expand Down
22 changes: 1 addition & 21 deletions docs/source/deployment/lambda.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ For the sake of this example, the following file can just be copied and pasted i
service: apollo-lambda
provider:
name: aws
runtime: nodejs12.x
runtime: nodejs14.x
functions:
graphql:
# this is formatted as <FILENAME>.<HANDLER>
Expand Down Expand Up @@ -252,23 +252,3 @@ exports.graphqlHandler = server.createHandler({
},
});
```

## Setting up GraphQL Playground

By default, `serverless` will deploy to AWS with the `stage` set to `development` resulting in an API endpoint at `/dev/graphql`.

To allow GraphQL Playground to correctly use the `dev` endpoint, add a new `endpoint` configuration within the `playground` option to the `ApolloServer` instantiation options:

```js
const server = new ApolloServer({
typeDefs,
resolvers,
// highlight-start
playground: {
endpoint: "/dev/graphql"
}
// highlight-end
});
```

For information on additional configuration options, see [GraphQL Playground](https://www.apollographql.com/docs/apollo-server/testing/graphql-playground/).
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion docs/source/integrations/middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,6 @@ async function startApolloServer() {

The parameter you provide to `applyMiddleware` is your middleware's top-level representation of your application. In Express applications, this variable is commonly named `app`.

When you pass your app to `applyMiddleware`, Apollo Server automatically configures various middleware (including body parsing, the GraphQL Playground frontend, and CORS support), so you don't need to apply them with a mechanism like `app.use`.
When you pass your app to `applyMiddleware`, Apollo Server automatically configures various middleware (including body parsing, an HTML UI, and CORS support), so you don't need to apply them with a mechanism like `app.use`.

> **Note:** When integrating with hapi, call `applyMiddleware` with `await`.
26 changes: 26 additions & 0 deletions docs/source/integrations/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,32 @@ const server = new ApolloServer({
})
```

### `renderUIPage`

The `renderUIPage` event is fired once by Apollo Server after all `serverWillStart` events run.
You define your `renderUIPage` handler in the object returned by your [`serverWillStart`](#serverwillstart) handler, which allows it to read the values passed to `serverWillStart`. **At most one plugin in your server may define a `renderUIPage` handler.** If your server has a `renderUIPage` handler, it should return a `UIPage`, which is just an object with a string `html` field. The value of that field will be served as HTML for any requests with `accept: text/html` headers. (By default, Apollo Server installs `ApolloServerPluginUIGraphQLPlayground` which serves GraphQL Playground as a UI page.)

#### Example

```js
const server = new ApolloServer({
/* ... other necessary configuration ... */

plugins: [
{
serverWillStart() {
return {
renderUIPage() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name of this just seems slightly askew from the patterns we've employed in the plugin API already. I don't know if I have a better suggestion.

Suggested change
renderUIPage() {
willRenderFrontend() {

Doesn't strike me as better. Then I suppose my next question is, in case it wasn't clear from my hesitation to use UI here is if Frontend was just more expressive.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that will/did makes sense here because it's not just an observability hook noting that something happened — it actually does the rendering.

return { html: `<html><body>Welcome to your server!</body></html>` };
}
}
}
}
]
})
```


### `requestDidStart`

The `requestDidStart` event fires whenever Apollo Server begins fulfilling a GraphQL request.
Expand Down
64 changes: 40 additions & 24 deletions docs/source/testing/graphql-playground.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,51 +20,67 @@ To try out dev graphs:

</ExpansionPanel>

[GraphQL Playground](https://github.com/prismagraphql/graphql-playground) is a graphical, interactive, in-browser GraphQL IDE, created by [Prisma](https://www.prisma.io/) and based on [GraphiQL](https://github.com/graphql/graphiql).
[GraphQL Playground](https://github.com/graphql/graphql-playground) is a graphical, interactive, in-browser GraphQL IDE, created by [Prisma](https://www.prisma.io/) and based on [GraphiQL](https://github.com/graphql/graphiql).

In development, Apollo Server enables GraphQL Playground on the same URL as the GraphQL server itself (e.g. `http://localhost:4000/graphql`) and automatically serves the GUI to web browsers. When `NODE_ENV` is set to `production`, GraphQL Playground (as well as introspection) is disabled as a production best-practice.
In development, Apollo Server enables GraphQL Playground on the same URL as the GraphQL server itself (e.g. `http://localhost:4000/graphql`) and automatically serves the GUI to web browsers. When `NODE_ENV` is set to `production`, GraphQL Playground (as well as introspection) is disabled as a production best-practice. It does this by installing the `ApolloServerPluginUIGraphQLPlayground` plugin with default settings.

![GraphQL Playground](../images/graphql-playground.png)

## Configuring Playground

The Apollo Server constructor contains the ability to configure GraphQL Playground with the `playground` configuration option. The options can be found on GraphQL Playground's [documentation](https://github.com/prismagraphql/graphql-playground/#usage).
If you'd like to configure playground, you can add `ApolloServerPluginUIGraphQLPlayground` to your Apollo Server yourself. contains the ability to configure GraphQL Playground with the `playground` configuration option. The options can be found on GraphQL Playground's [documentation](https://github.com/graphql/graphql-playground/#usage).
glasser marked this conversation as resolved.
Show resolved Hide resolved

```js
const { ApolloServer } = require('apollo-server');
const { ApolloServerPluginUIGraphQLPlayground } = require('apollo-server-core');

new ApolloServer({
typeDefs,
resolvers,
playground: {
settings: {
'editor.theme': 'light',
},
tabs: [
{
endpoint,
query: defaultQuery,
},
typeDefs,
resolvers,
plugins: [
ApolloServerPluginUIGraphQLPlayground({
settings: {
'editor.theme': 'light',
},
tabs: [
{
endpoint,
query: defaultQuery,
},
],
}),
],
},
});
```

## Enabling GraphQL Playground in production
## Disabling Playground in development

To enable GraphQL Playground in production, introspection and the playground can be enabled explicitly in the following manner.
If you don't want to run GraphQL Playground at all, you have two choices. First, you can replace it with a different UI by installing a plugin that implements the [`renderUIPage` event](../integrations/plugins/#renderuipage). Alternatively, you can install the `ApolloServerPluginUIDisabled` plugin which stops Apollo Server from serving any HTML UI.
glasser marked this conversation as resolved.
Show resolved Hide resolved

```js{7-8}
```js
const { ApolloServer } = require('apollo-server');
const { typeDefs, resolvers } = require('./schema');
const { ApolloServerPluginUIDisabled } = require('apollo-server-core');

const server = new ApolloServer({
new ApolloServer({
typeDefs,
resolvers,
introspection: true,
playground: true,
plugins: [ApolloServerPluginUIDisabled()],
});
```

## Enabling GraphQL Playground in production

server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
To enable GraphQL Playground in production, just install GraphQL Playground yourself, without any special configuration. You should also enable introspection so that GraphQL Playground can load your graph's schema.

```js
const { ApolloServer } = require('apollo-server');
const { ApolloServerPluginUIGraphQLPlayground } = require('apollo-server-core');

new ApolloServer({
typeDefs,
resolvers,
introspection: true,
plugins: [ApolloServerPluginUIGraphQLPlayground()],
});

```
Loading