diff --git a/docs/aiohttp.md b/docs/aiohttp.md index be38ff5..b301855 100644 --- a/docs/aiohttp.md +++ b/docs/aiohttp.md @@ -52,7 +52,7 @@ gql_view(request) # <-- the instance is callable and expects a `aiohttp.web.Req * `root_value`: The `root_value` you want to provide to graphql `execute`. * `pretty`: Whether or not you want the response to be pretty printed JSON. * `graphiql`: If `True`, may present [GraphiQL](https://github.com/graphql/graphiql) when loaded directly from a browser (a useful tool for debugging and exploration). - * `graphiql_version`: The graphiql version to load. Defaults to **"1.4.7"**. + * `graphiql_version`: The graphiql version to load. Defaults to **"2.2.0"**. * `graphiql_template`: Inject a Jinja template string to customize GraphiQL. * `graphiql_html_title`: The graphiql title to display. Defaults to **"GraphiQL"**. * `jinja_env`: Sets jinja environment to be used to process GraphiQL template. If Jinja’s async mode is enabled (by `enable_async=True`), uses `Template.render_async` instead of `Template.render`. If environment is not set, fallbacks to simple regex-based renderer. diff --git a/docs/flask.md b/docs/flask.md index 0c4125f..dfe0aa7 100644 --- a/docs/flask.md +++ b/docs/flask.md @@ -46,9 +46,10 @@ This will add `/graphql` endpoint to your app and enable the GraphiQL IDE. * `root_value`: The `root_value` you want to provide to graphql `execute`. * `pretty`: Whether or not you want the response to be pretty printed JSON. * `graphiql`: If `True`, may present [GraphiQL](https://github.com/graphql/graphiql) when loaded directly from a browser (a useful tool for debugging and exploration). - * `graphiql_version`: The graphiql version to load. Defaults to **"1.4.7"**. + * `graphiql_version`: The graphiql version to load. Defaults to **"2.2.0"**. * `graphiql_template`: Inject a Jinja template string to customize GraphiQL. * `graphiql_html_title`: The graphiql title to display. Defaults to **"GraphiQL"**. + * `jinja_env`: Sets jinja environment to be used to process GraphiQL template. If environment is not set, fallbacks to simple regex-based renderer. * `batch`: Set the GraphQL view as batch (for using in [Apollo-Client](http://dev.apollodata.com/core/network.html#query-batching) or [ReactRelayNetworkLayer](https://github.com/nodkz/react-relay-network-layer)) * `middleware`: A list of graphql [middlewares](http://docs.graphene-python.org/en/latest/execution/middleware/). * `validation_rules`: A list of graphql validation rules. diff --git a/docs/sanic.md b/docs/sanic.md index 39c20af..102e38d 100644 --- a/docs/sanic.md +++ b/docs/sanic.md @@ -44,7 +44,7 @@ This will add `/graphql` endpoint to your app and enable the GraphiQL IDE. * `root_value`: The `root_value` you want to provide to graphql `execute`. * `pretty`: Whether or not you want the response to be pretty printed JSON. * `graphiql`: If `True`, may present [GraphiQL](https://github.com/graphql/graphiql) when loaded directly from a browser (a useful tool for debugging and exploration). - * `graphiql_version`: The graphiql version to load. Defaults to **"1.4.7"**. + * `graphiql_version`: The graphiql version to load. Defaults to **"2.2.0"**. * `graphiql_template`: Inject a Jinja template string to customize GraphiQL. * `graphiql_html_title`: The graphiql title to display. Defaults to **"GraphiQL"**. * `jinja_env`: Sets jinja environment to be used to process GraphiQL template. If Jinja’s async mode is enabled (by `enable_async=True`), uses `Template.render_async` instead of `Template.render`. If environment is not set, fallbacks to simple regex-based renderer. diff --git a/docs/webob.md b/docs/webob.md index d84e07d..2f88a31 100644 --- a/docs/webob.md +++ b/docs/webob.md @@ -43,9 +43,10 @@ This will add `/graphql` endpoint to your app and enable the GraphiQL IDE. * `root_value`: The `root_value` you want to provide to graphql `execute`. * `pretty`: Whether or not you want the response to be pretty printed JSON. * `graphiql`: If `True`, may present [GraphiQL](https://github.com/graphql/graphiql) when loaded directly from a browser (a useful tool for debugging and exploration). - * `graphiql_version`: The graphiql version to load. Defaults to **"1.4.7"**. + * `graphiql_version`: The graphiql version to load. Defaults to **"2.2.0"**. * `graphiql_template`: Inject a Jinja template string to customize GraphiQL. * `graphiql_html_title`: The graphiql title to display. Defaults to **"GraphiQL"**. + * `jinja_env`: Sets jinja environment to be used to process GraphiQL template. If environment is not set, fallbacks to simple regex-based renderer. * `batch`: Set the GraphQL view as batch (for using in [Apollo-Client](http://dev.apollodata.com/core/network.html#query-batching) or [ReactRelayNetworkLayer](https://github.com/nodkz/react-relay-network-layer)) * `middleware`: A list of graphql [middlewares](http://docs.graphene-python.org/en/latest/execution/middleware/). * `validation_rules`: A list of graphql validation rules. diff --git a/graphql_server/__init__.py b/graphql_server/__init__.py index 9a58a9f..f8456de 100644 --- a/graphql_server/__init__.py +++ b/graphql_server/__init__.py @@ -335,3 +335,17 @@ def format_execution_result( response = {"data": execution_result.data} return FormattedResult(response, status_code) + + +def _check_jinja(jinja_env: Any) -> None: + try: + from jinja2 import Environment + except ImportError: # pragma: no cover + raise RuntimeError( + "Attempt to set 'jinja_env' to a value other than None while Jinja2 is not installed.\n" + "Please install Jinja2 to render GraphiQL with Jinja2.\n" + "Otherwise set 'jinja_env' to None to use the simple regex renderer." + ) + + if not isinstance(jinja_env, Environment): # pragma: no cover + raise TypeError("'jinja_env' has to be of type jinja2.Environment.") diff --git a/graphql_server/aiohttp/graphqlview.py b/graphql_server/aiohttp/graphqlview.py index b5891d1..8e0dbd5 100644 --- a/graphql_server/aiohttp/graphqlview.py +++ b/graphql_server/aiohttp/graphqlview.py @@ -12,6 +12,7 @@ from graphql_server import ( GraphQLParams, HttpQueryError, + _check_jinja, encode_execution_results, format_error_default, json_encode, @@ -66,6 +67,9 @@ def __init__(self, **kwargs): if not isinstance(self.schema, GraphQLSchema): raise TypeError("A Schema is required to be provided to GraphQLView.") + if self.jinja_env is not None: + _check_jinja(self.jinja_env) + def get_root_value(self): return self.root_value diff --git a/graphql_server/flask/graphqlview.py b/graphql_server/flask/graphqlview.py index 4bb4665..6132b61 100644 --- a/graphql_server/flask/graphqlview.py +++ b/graphql_server/flask/graphqlview.py @@ -12,6 +12,7 @@ from graphql_server import ( GraphQLParams, HttpQueryError, + _check_jinja, encode_execution_results, format_error_default, json_encode, @@ -39,6 +40,7 @@ class GraphQLView(View): validation_rules = None execution_context_class = None batch = False + jinja_env = None subscriptions = None headers = None default_query = None @@ -62,6 +64,9 @@ def __init__(self, **kwargs): if not isinstance(self.schema, GraphQLSchema): raise TypeError("A Schema is required to be provided to GraphQLView.") + if self.jinja_env is not None: + _check_jinja(self.jinja_env) + def get_root_value(self): return self.root_value @@ -131,7 +136,7 @@ def dispatch_request(self): graphiql_version=self.graphiql_version, graphiql_template=self.graphiql_template, graphiql_html_title=self.graphiql_html_title, - jinja_env=None, + jinja_env=self.jinja_env, ) graphiql_options = GraphiQLOptions( default_query=self.default_query, diff --git a/graphql_server/quart/graphqlview.py b/graphql_server/quart/graphqlview.py index d7b209f..acf90f4 100644 --- a/graphql_server/quart/graphqlview.py +++ b/graphql_server/quart/graphqlview.py @@ -14,6 +14,7 @@ from graphql_server import ( GraphQLParams, HttpQueryError, + _check_jinja, encode_execution_results, format_error_default, json_encode, @@ -42,6 +43,7 @@ class GraphQLView(View): validation_rules = None execution_context_class = None batch = False + jinja_env = None enable_async = False subscriptions = None headers = None @@ -66,6 +68,9 @@ def __init__(self, **kwargs): if not isinstance(self.schema, GraphQLSchema): raise TypeError("A Schema is required to be provided to GraphQLView.") + if self.jinja_env is not None: + _check_jinja(self.jinja_env) + def get_root_value(self): return self.root_value @@ -147,7 +152,7 @@ async def dispatch_request(self): graphiql_version=self.graphiql_version, graphiql_template=self.graphiql_template, graphiql_html_title=self.graphiql_html_title, - jinja_env=None, + jinja_env=self.jinja_env, ) graphiql_options = GraphiQLOptions( default_query=self.default_query, diff --git a/graphql_server/render_graphiql.py b/graphql_server/render_graphiql.py index 498f53b..0da06b9 100644 --- a/graphql_server/render_graphiql.py +++ b/graphql_server/render_graphiql.py @@ -1,13 +1,19 @@ """Based on (express-graphql)[https://github.com/graphql/express-graphql/blob/main/src/renderGraphiQL.ts] and -(subscriptions-transport-ws)[https://github.com/apollographql/subscriptions-transport-ws]""" +(graphql-ws)[https://github.com/enisdenjo/graphql-ws]""" import json import re from typing import Any, Dict, Optional, Tuple -from jinja2 import Environment +# This Environment import is only for type checking purpose, +# and only relevant if rendering GraphiQL with Jinja +try: + from jinja2 import Environment +except ImportError: # pragma: no cover + pass + from typing_extensions import TypedDict -GRAPHIQL_VERSION = "1.4.7" +GRAPHIQL_VERSION = "2.2.0" GRAPHIQL_TEMPLATE = """