1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//! Utility module to generate a GraphiQL interface

/// Generate the HTML source to show a GraphiQL interface
///
/// The subscriptions endpoint URL can optionally be provided. For example:
///
/// ```
/// # use juniper::http::graphiql::graphiql_source;
/// let graphiql = graphiql_source("/graphql", Some("ws://localhost:8080/subscriptions"));
/// ```
pub fn graphiql_source(
    graphql_endpoint_url: &str,
    subscriptions_endpoint_url: Option<&str>,
) -> String {
    let subscriptions_endpoint = if let Some(sub_url) = subscriptions_endpoint_url {
        sub_url
    } else {
        ""
    };

    let stylesheet_source = r#"
    <style>
        html, body, #app {
            height: 100%;
            margin: 0;
            overflow: hidden;
            width: 100%;
        }
    </style>
    "#;
    let fetcher_source = r#"
    <script>
        if (usingSubscriptions) {
            var subscriptionEndpoint = normalizeSubscriptionEndpoint(GRAPHQL_URL, GRAPHQL_SUBSCRIPTIONS_URL);
            var subscriptionsClient = new window.SubscriptionsTransportWs.SubscriptionClient(subscriptionEndpoint, { reconnect: true });
        }

        function normalizeSubscriptionEndpoint(endpoint, subscriptionEndpoint) {
            if (subscriptionEndpoint) {
                if (subscriptionEndpoint.startsWith('/')) {
                    const secure =
                        endpoint.includes('https') || location.href.includes('https')
                        ? 's'
                        : ''
                    return `ws${secure}://${location.host}${subscriptionEndpoint}`
                } else {
                    return subscriptionEndpoint.replace(/^http/, 'ws')
                }
            }
            return null
        }

        function graphQLFetcher(params) {
            return fetch(GRAPHQL_URL, {
                method: 'post',
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/json',
                },
                credentials: 'include',
                body: JSON.stringify(params)
            }).then(function (response) {
                return response.text();
            }).then(function (body) {
                try {
                    return JSON.parse(body);
                } catch (error) {
                    return body;
                }
            });
        }

        var fetcher = usingSubscriptions ? window.GraphiQLSubscriptionsFetcher.graphQLFetcher(subscriptionsClient, graphQLFetcher) : graphQLFetcher;

        ReactDOM.render(
            React.createElement(GraphiQL, {
                fetcher,
            }),
            document.querySelector('#app'));
    </script>
    "#;

    format!(
        r#"
<!DOCTYPE html>
<html>
<head>
    <title>GraphQL</title>
    {stylesheet_source}
    <link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/graphiql@0.17.5/graphiql.min.css">
</head>
<body>
    <div id="app"></div>
    <script src="//cdnjs.cloudflare.com/ajax/libs/fetch/2.0.3/fetch.js"></script>
    <script src="//unpkg.com/subscriptions-transport-ws@0.8.3/browser/client.js"></script>
    <script src="//unpkg.com/graphiql-subscriptions-fetcher@0.0.2/browser/client.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/react/16.10.2/umd/react.production.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.2/umd/react-dom.production.min.js"></script>
    <script src="//cdn.jsdelivr.net/npm/graphiql@0.17.5/graphiql.min.js"></script>
    <script>var GRAPHQL_URL = '{graphql_url}';</script>
    <script>var usingSubscriptions = {using_subscriptions};</script>
    <script>var GRAPHQL_SUBSCRIPTIONS_URL = '{graphql_subscriptions_url}';</script>
    {fetcher_source}
</body>
</html>
"#,
        graphql_url = graphql_endpoint_url,
        stylesheet_source = stylesheet_source,
        fetcher_source = fetcher_source,
        graphql_subscriptions_url = subscriptions_endpoint,
        using_subscriptions = subscriptions_endpoint_url.is_some(),
    )
}