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

Update GraphiQL default version #262

Closed
frisi opened this issue Apr 12, 2022 · 2 comments · Fixed by #458
Closed

Update GraphiQL default version #262

frisi opened this issue Apr 12, 2022 · 2 comments · Fixed by #458
Assignees
Labels
info: good first issue Good for newcomers status: pr submitted A pull request has been submitted for the issue

Comments

@frisi
Copy link

frisi commented Apr 12, 2022

Feature description

the currently used default version of graphiql (0.13.2) dates back to 2019

using recent versions (eg v1.0.0 added a request header editor) does not work as CDN URLs changed and also react needs to be updated.

i customized my local setup using the below template and application.yml
evtl somebody is willing to put this into a new micronaut-graphql release

graphql:
  graphiql:
    version: 1.8.5
    template-path: classpath:graphiql/index-custom.html

graphiql/index-custom.html:

<!--
 based on cdn example https://github.com/graphql/graphiql/blob/main/examples/graphiql-cdn/index.html

 with adaptions from micronaut's graphiql client
 https://github.com/micronaut-projects/micronaut-graphql/blob/master/graphql/src/main/resources/graphiql/index.html

 and also pass headers to the fetcher
  https://github.com/graphql/graphiql/issues/59#issuecomment-914079822

 *  Copyright (c) 2021 GraphQL Contributors
 *  All rights reserved.
 *
 *  This source code is licensed under the license found in the
 *  LICENSE file in the root directory of this source tree.
-->
<!DOCTYPE html>
<html>
<head>
    <title>${pageTitle}</title>
    <style>
      body {
        height: 100%;
        margin: 0;
        width: 100%;
        overflow: hidden;
      }

      #graphiql {
        height: 100vh;
      }
    </style>

    <!--
      This GraphiQL example depends on Promise and fetch, which are available in
      modern browsers, but can be "polyfilled" for older browsers.
      GraphiQL itself depends on React DOM.
      If you do not want to rely on a CDN, you can host these files locally or
      include them directly in your favored resource bunder.
    -->
    <script
            crossorigin
            src="https://unpkg.com/react@16/umd/react.development.js"
    ></script>
    <script
            crossorigin
            src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"
    ></script>

    <!--
      These two files can be found in the npm module, however you may wish to
      copy them directly into your environment, or perhaps include them in your
      favored resource bundler.
     -->
    <link rel="stylesheet" href="https://unpkg.com/graphiql@${graphiqlVersion}/graphiql.min.css" />
</head>

<body>
<div id="graphiql">Loading...</div>
<script
        src="https://unpkg.com/graphiql@${graphiqlVersion}/graphiql.min.js"
        type="application/javascript"
></script>

<script>

    // Parse the search string to get url parameters.
    var search = window.location.search;
    var parameters = {};
    search.substr(1).split('&').forEach(function (entry) {
        var eq = entry.indexOf('=');
        if (eq >= 0) {
            parameters[decodeURIComponent(entry.slice(0, eq))] =
                decodeURIComponent(entry.slice(eq + 1));
        }
    });

    // If variables was provided, try to format it.
    if (parameters.variables) {
        try {
            parameters.variables =
                JSON.stringify(JSON.parse(parameters.variables), null, 2);
        } catch (e) {
            // Do nothing, we want to display the invalid JSON as a string, rather
            // than present an error.
        }
    }

    // When the query and variables string is edited, update the URL bar so
    // that it can be easily shared.
    function onEditQuery(newQuery) {
        parameters.query = newQuery;
        updateURL();
    }

    function onEditVariables(newVariables) {
        parameters.variables = newVariables;
        updateURL();
    }

    function onEditOperationName(newOperationName) {
        parameters.operationName = newOperationName;
        updateURL();
    }

    function updateURL() {
        var newSearch = '?' + Object.keys(parameters).filter(function (key) {
            return Boolean(parameters[key]);
        }).map(function (key) {
            return encodeURIComponent(key) + '=' +
                encodeURIComponent(parameters[key]);
        }).join('&');
        history.replaceState(null, null, newSearch);
    }

    // return path to service from current URL where GraphiQL was invoked
    function pathToService() {
        let graphiqlPath = '${graphiqlPath}'
        let graphiqlPathLength = graphiqlPath.length
        let removePathLength = window.location.pathname.endsWith('/') && !graphiqlPath.endsWith('/')
            ? graphiqlPathLength + 1
            : graphiqlPathLength;

        return window.location.pathname.substr(0, window.location.pathname.length - removePathLength);
    }

      function graphQLFetcher(graphQLParams, opts) {
        const { headers = {} } = opts;
        return fetch(
          pathToService() + '${graphqlPath}',
          {
            method: 'post',
            headers: {
              Accept: 'application/json',
              'Content-Type': 'application/json',
              ...headers,
            },
            body: JSON.stringify(graphQLParams),
            credentials: 'include',
          },
        ).then(function (response) {
          return response.json().catch(function () {
            return response.text();
          });
        });
      }

    let fetcher = graphQLFetcher;
    if('${graphqlWsPath}' !== ''){
      let wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
      let fullWsPath = wsProtocol + '//' + window.location.hostname + ':' + window.location.port + pathToService() +'${graphqlWsPath}';
      let subscriptionsClient = new window.SubscriptionsTransportWs.SubscriptionClient(fullWsPath, { reconnect: true });
      fetcher = window.GraphiQLSubscriptionsFetcher.graphQLFetcher(subscriptionsClient, graphQLFetcher);
    }

      ReactDOM.render(
        React.createElement(GraphiQL, {
          fetcher: fetcher,
          query: parameters.query,
          defaultVariableEditorOpen: true,
          variables: parameters.variables,
            operationName: parameters.operationName,
            onEditQuery: onEditQuery,
            onEditVariables: onEditVariables,
            defaultVariableEditorOpen: true,
            onEditOperationName: onEditOperationName
        }),
        document.getElementById('graphiql'),
      );
    </script>
</body>
</html>

@alvarosanchez alvarosanchez changed the title Update GraphiQL Update GraphiQL default version Apr 13, 2022
@alvarosanchez
Copy link
Member

@frisi thank you very much for raising this. Would you be willing to contribute this yourself in a pull request?

@alvarosanchez alvarosanchez added the info: good first issue Good for newcomers label Apr 13, 2022
@frisi
Copy link
Author

frisi commented Apr 14, 2022

sorry alvaro. i currently lack time for this but will put it on my list of things that "possibly might happen" ;-)

i also found that the documentation is misleading.

Either by providing the custom template at src/main/resources/graphiq/index.html or via the graphiql.template-path application property pointing to a different template location.

using the same name for the template worked on my local setup but not for deployments (seems the order the resource classpath:graphiql/index.html is looked up is arbitratry and there is no guarantee the custom on is used)
i guess the documentation should be changed, what do you think @alvarosanchez

i'll update the description also with an updated template that also passes the custom headers to the fetcher (see also graphql/graphiql#59 (comment))

@guillermocalvo guillermocalvo self-assigned this Oct 5, 2023
@guillermocalvo guillermocalvo linked a pull request Oct 6, 2023 that will close this issue
@guillermocalvo guillermocalvo added the status: pr submitted A pull request has been submitted for the issue label Oct 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
info: good first issue Good for newcomers status: pr submitted A pull request has been submitted for the issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants