Skip to content

add support to pass properties to graphiql. For now only editorTheme #93

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

Merged
merged 1 commit into from
Apr 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,12 @@ The `graphqlHTTP` function accepts the following options:
* **`schema`**: A `GraphQLSchema` instance from [`graphql-js`][].
A `schema` *must* be provided.

* **`graphiql`**: If `true`, presents [GraphiQL][] when the route with a
* **`graphiql`**: If `true` or `object`, presents [GraphiQL][] when the route with a
`/graphiql` appended is loaded in a browser. We recommend that you set
`graphiql` to `true` when your app is in development, because it's
quite useful. You may or may not want it in production.
quite useful. By passing an object you may change the theme of GraphiQL.
Details are below in the [Custom GraphiQL themes](#custom-graphiql-themes) section.
You may or may not want to turn on GraphiQL in production.

* **`rootValue`**: A value to pass as the `rootValue` to the `graphql()`
function from [`graphql-js/src/execute.js`](https://github.com/graphql/graphql-js/blob/master/src/execution/execute.js#L122).
Expand Down Expand Up @@ -248,6 +250,36 @@ for example:
}
```

## Custom GraphiQL themes

To use custom GraphiQL theme you should pass to `graphiql` option an object with
the property `editorTheme`. It could be a string with the name of a theme from `CodeMirror`
```js
router.all('/graphql', graphqlHTTP({
schema: MyGraphQLSchema,
graphiql: {
editorTheme: 'blackboard'
}
}));
```
[List of available CodeMirror themas](https://codemirror.net/demo/theme.html)

or an object with `url` and `name` properties where `url` should lead to
your custom theme and `name` would be passed to the `GraphiQL`
react element on creation as the `editorTheme` property
```js
router.all('/graphql', graphqlHTTP({
schema: MyGraphQLSchema,
graphiql: {
editorTheme: {
name: 'blackboard',
url: 'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.53.2/theme/erlang-dark.css'
}
}
}));
```
For details see the [GraphiQL spec](https://github.com/graphql/graphiql/tree/master/packages/graphiql#applying-an-editor-theme)


## Additional Validation Rules

Expand Down
6 changes: 3 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export type OptionsData = {
/**
* A boolean to optionally enable GraphiQL mode.
*/
graphiql?: ?boolean,
graphiql?: ?boolean | {},

/**
* A resolver function to use when one is not provided by the schema.
Expand Down Expand Up @@ -310,12 +310,12 @@ function graphqlHTTP(options: Options): Middleware {

// If allowed to show GraphiQL, present it instead of JSON.
if (showGraphiQL) {
const payload = renderGraphiQL({
const payload = renderGraphiQL(Object.assign({
query,
variables,
operationName,
result,
});
}, graphiql));
response.type = 'text/html';
response.body = payload;
} else {
Expand Down
40 changes: 40 additions & 0 deletions src/renderGraphiQL.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,57 @@
/* @flow strict */

type EditorThemeParam = {
name: string,
url: string,
} | string;

type GraphiQLData = {
query: ?string,
variables: ?{ [param: string]: mixed },
operationName: ?string,
result?: mixed,
editorTheme?: EditorThemeParam
};

type EditorTheme = {
name: string,
link: string
} | {};

// Current latest version of GraphiQL.
const GRAPHIQL_VERSION = '0.17.5';
// Current latest version of codeMirror.
const CODE_MIRROR_VERSION = '5.53.2';

// Ensures string values are safe to be used within a <script> tag.
function safeSerialize(data): string {
return data ? JSON.stringify(data).replace(/\//g, '\\/') : 'undefined';
}

function getEditorThemeParams(editorTheme: EditorThemeParam): EditorTheme {
if (!editorTheme) {
return {};
}
if (typeof editorTheme === 'string') {
return {
name: editorTheme,
link: `<link href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/${CODE_MIRROR_VERSION}/theme/${editorTheme}.css" rel="stylesheet" />`
};
}
if (typeof editorTheme === 'object' &&
editorTheme.name && typeof editorTheme.name === 'string' &&
editorTheme.url && typeof editorTheme.url === 'string'
) {
return {
link: `<link href="${editorTheme.url}" rel="stylesheet" />`,
name: editorTheme.name
};
}
throw Error('invalid parameter "editorTheme": should be undefined/null, string or ' +
`{name: string, url: string} but provided is "${editorTheme}"`
);
}

/**
* When express-graphql receives a request which does not Accept JSON, but does
* Accept HTML, it may present GraphiQL, the in-browser GraphQL explorer IDE.
Expand All @@ -31,6 +68,7 @@ export function renderGraphiQL(data: GraphiQLData): string {
? JSON.stringify(data.result, null, 2)
: null;
const operationName = data.operationName;
const editorTheme = getEditorThemeParams(data.editorTheme);

return `<!--
The request to this GraphQL server provided the header "Accept: text/html"
Expand All @@ -57,6 +95,7 @@ add "&raw" to the end of the URL within a browser.
}
</style>
<link href="//cdn.jsdelivr.net/npm/graphiql@${GRAPHIQL_VERSION}/graphiql.css" rel="stylesheet" />
${editorTheme.link || ''}
<script src="//cdn.jsdelivr.net/es6-promise/4.0.5/es6-promise.auto.min.js"></script>
<script src="//cdn.jsdelivr.net/fetch/0.9.0/fetch.min.js"></script>
<script src="//cdn.jsdelivr.net/react/15.4.2/react.min.js"></script>
Expand Down Expand Up @@ -140,6 +179,7 @@ add "&raw" to the end of the URL within a browser.
onEditQuery: onEditQuery,
onEditVariables: onEditVariables,
onEditOperationName: onEditOperationName,
editorTheme: ${editorTheme.name && safeSerialize(editorTheme.name)},
query: ${safeSerialize(queryString)},
response: ${safeSerialize(resultString)},
variables: ${safeSerialize(variablesString)},
Expand Down