diff --git a/.coveragerc b/.coveragerc
deleted file mode 100644
index 87df271..0000000
--- a/.coveragerc
+++ /dev/null
@@ -1,2 +0,0 @@
-[report]
-omit = */tests/*
diff --git a/.gitignore b/.gitignore
index 8f0e0ae..642f015 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,11 +1,204 @@
-*.pyc
-.idea
-.cache
-.tox
+
+# Created by https://www.gitignore.io/api/python,intellij+all,visualstudiocode
+# Edit at https://www.gitignore.io/?templates=python,intellij+all,visualstudiocode
+
+### Intellij+all ###
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn. Uncomment if using
+# auto-import.
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+# *.iml
+# *.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
+### Intellij+all Patch ###
+# Ignores the whole .idea folder and all .iml files
+# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
+
+.idea/
+
+# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
+
+*.iml
+modules.xml
+.idea/misc.xml
+*.ipr
+
+# Sonarlint plugin
+.idea/sonarlint
+
+### Python ###
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+pip-wheel-metadata/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
*.egg
-*.egg-info
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.venv/
.coverage
-/build/
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# pyenv
+.python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# Mr Developer
+.mr.developer.cfg
+.project
+.pydevproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+### VisualStudioCode ###
+.vscode
+
+### VisualStudioCode Patch ###
+# Ignore all local history of files
+.history
-/dist/
-/.pytest_cache
+# End of https://www.gitignore.io/api/python,intellij+all,visualstudiocode
diff --git a/.travis.yml b/.travis.yml
index c59b86e..52554b1 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,11 +1,9 @@
language: python
sudo: false
python:
- - 2.7
- - 3.5
- 3.6
- 3.7
- # - 3.8
+ - 3.8
cache: pip
install:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
deleted file mode 100644
index db93994..0000000
--- a/CONTRIBUTING.md
+++ /dev/null
@@ -1,94 +0,0 @@
-# Contributing
-
-Thanks for helping to make flask-graphql awesome!
-
-We welcome all kinds of contributions:
-
-- Bug fixes
-- Documentation improvements
-- New features
-- Refactoring & tidying
-
-
-## Getting started
-
-If you have a specific contribution in mind, be sure to check the [issues](https://github.com/graphql-python/flask-graphql/issues) and [pull requests](https://github.com/graphql-python/flask-graphql/pulls) in progress - someone could already be working on something similar and you can help out.
-
-
-## Project setup
-
-### Development with virtualenv (recommended)
-
-After cloning this repo, create a virtualenv:
-
-```console
-virtualenv flask-graphql-dev
-```
-
-Activate the virtualenv and install dependencies by running:
-
-```console
-python pip install -e ".[test]"
-```
-
-If you are using Linux or MacOS, you can make use of Makefile command
-`make dev-setup`, which is a shortcut for the above python command.
-
-### Development on Conda
-
-You must create a new env (e.g. `flask-graphql-dev`) with the following command:
-
-```sh
-conda create -n flask-graphql-dev python=3.8
-```
-
-Then activate the environment with `conda activate flask-graphql-dev`.
-
-Proceed to install all dependencies by running:
-
-```console
-python pip install -e ".[test]"
-```
-
-And you ready to start development!
-
-## Running tests
-
-After developing, the full test suite can be evaluated by running:
-
-```sh
-pytest tests --cov=flask_graphql -vv
-```
-
-If you are using Linux or MacOS, you can make use of Makefile command
-`make tests`, which is a shortcut for the above python command.
-
-You can also test on several python environments by using tox.
-
-### Running tox on virtualenv
-
-Install tox:
-
-```console
-pip install tox
-```
-
-Run `tox` on your virtualenv (do not forget to activate it!)
-and that's it!
-
-### Running tox on Conda
-
-In order to run `tox` command on conda, install
-[tox-conda](https://github.com/tox-dev/tox-conda):
-
-```sh
-conda install -c conda-forge tox-conda
-```
-
-This install tox underneath so no need to install it before.
-
-Then uncomment the `requires = tox-conda` line on `tox.ini` file.
-
-Run `tox` and you will see all the environments being created
-and all passing tests. :rocket:
-
diff --git a/MANIFEST.in b/MANIFEST.in
index 29c54bf..0fa13a1 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,14 +1,10 @@
include LICENSE
include README.md
-include CONTRIBUTING.md
-
-recursive-include flask_graphql/static *
-recursive-include flask_graphql/templates *
-recursive-include tests *.py
+include tox.ini
include Makefile
-include .coveragerc
-include tox.ini
+recursive-include flask_graphql *.py
+recursive-include tests *.py
global-exclude *.py[co] __pycache__
diff --git a/README.md b/README.md
index af4e1ac..3546b1d 100644
--- a/README.md
+++ b/README.md
@@ -21,26 +21,58 @@ Adds GraphQL support to your Flask application.
Just use the `GraphQLView` view from `flask_graphql`
```python
+from flask import Flask
from flask_graphql import GraphQLView
-app.add_url_rule('/graphql', view_func=GraphQLView.as_view('graphql', schema=schema, graphiql=True))
+from schema import schema
+
+app = Flask(__name__)
+
+app.add_url_rule('/graphql', view_func=GraphQLView.as_view(
+ 'graphql',
+ schema=schema,
+ graphiql=True,
+))
# Optional, for adding batch query support (used in Apollo-Client)
-app.add_url_rule('/graphql/batch', view_func=GraphQLView.as_view('graphql', schema=schema, batch=True))
+app.add_url_rule('/graphql/batch', view_func=GraphQLView.as_view(
+ 'graphql',
+ schema=schema,
+ batch=True
+))
+
+if __name__ == '__main__':
+ app.run()
```
-This will add `/graphql` and `/graphiql` endpoints to your app.
+This will add `/graphql` endpoint to your app and enable the GraphiQL IDE.
+
+### Special Note for Graphene v3
+
+If you are using the `Schema` type of [Graphene](https://github.com/graphql-python/graphene) library, be sure to use the `graphql_schema` attribute to pass as schema on the `GraphQLView` view. Otherwise, the `GraphQLSchema` from `graphql-core` is the way to go.
+
+More info at [Graphene v3 release notes](https://github.com/graphql-python/graphene/wiki/v3-release-notes#graphene-schema-no-longer-subclasses-graphqlschema-type) and [GraphQL-core 3 usage](https://github.com/graphql-python/graphql-core#usage).
+
+
+### Supported options for GraphQLView
-### Supported options
* `schema`: The `GraphQLSchema` object that you want the view to execute when it gets a valid request.
- * `context`: A value to pass as the `context` to the `graphql()` function.
- * `root_value`: The `root_value` you want to provide to `executor.execute`.
+ * `context`: A value to pass as the `context_value` to graphql `execute` function. By default is set to `dict` with request object at key `request`.
+ * `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.
- * `executor`: The `Executor` that you want to use to execute queries.
* `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.0.3"**.
* `graphiql_template`: Inject a Jinja template string to customize GraphiQL.
+ * `graphiql_html_title`: The graphiql title to display. Defaults to **"GraphiQL"**.
* `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/).
+ * `encode`: the encoder to use for responses (sensibly defaults to `graphql_server.json_encode`).
+ * `format_error`: the error formatter to use for responses (sensibly defaults to `graphql_server.default_format_error`.
+ * `subscriptions`: The GraphiQL socket endpoint for using subscriptions in graphql-ws.
+ * `headers`: An optional GraphQL string to use as the initial displayed request headers, if not provided, the stored headers will be used.
+ * `default_query`: An optional GraphQL string to use when no query is provided and no stored query exists from a previous session. If not provided, GraphiQL will use its own default query.
+* `header_editor_enabled`: An optional boolean which enables the header editor when true. Defaults to **false**.
+* `should_persist_headers`: An optional boolean which enables to persist headers to storage when true. Defaults to **false**.
You can also subclass `GraphQLView` and overwrite `get_root_value(self, request)` to have a dynamic root value
per request.
@@ -53,4 +85,4 @@ class UserRootValue(GraphQLView):
```
## Contributing
-See [CONTRIBUTING.md](CONTRIBUTING.md)
+Since v3, `flask-graphql` code lives at [graphql-server](https://github.com/graphql-python/graphql-server) repository to keep any breaking change on the base package on sync with all other integrations. In order to contribute, please take a look at [CONTRIBUTING.md](https://github.com/graphql-python/graphql-server/blob/master/CONTRIBUTING.md).
diff --git a/flask_graphql/__init__.py b/flask_graphql/__init__.py
index 4c30423..5b3ee3c 100644
--- a/flask_graphql/__init__.py
+++ b/flask_graphql/__init__.py
@@ -1,4 +1,3 @@
-from .blueprint import GraphQL
-from .graphqlview import GraphQLView
+from graphql_server.flask.graphqlview import GraphQLView
-__all__ = ['GraphQL', 'GraphQLView']
+__all__ = ['GraphQLView']
diff --git a/flask_graphql/blueprint.py b/flask_graphql/blueprint.py
deleted file mode 100644
index b02266a..0000000
--- a/flask_graphql/blueprint.py
+++ /dev/null
@@ -1,17 +0,0 @@
-import warnings
-
-from flask import Blueprint
-
-from .graphqlview import GraphQLView
-
-
-class GraphQL(object):
- def __init__(self, app, schema, **options):
- self.app = app
- warnings.warn('GraphQL Blueprint is now deprecated, please use GraphQLView directly')
- self.blueprint = Blueprint('graphql', __name__,
- template_folder='templates')
-
- app.add_url_rule('/graphql', view_func=GraphQLView.as_view('graphql', schema=schema, **options))
-
- self.app.register_blueprint(self.blueprint)
diff --git a/flask_graphql/graphqlview.py b/flask_graphql/graphqlview.py
deleted file mode 100644
index 25e382f..0000000
--- a/flask_graphql/graphqlview.py
+++ /dev/null
@@ -1,154 +0,0 @@
-from functools import partial
-
-from flask import Response, request
-from flask.views import View
-from graphql_server import (HttpQueryError, default_format_error,
- encode_execution_results, json_encode,
- load_json_body, run_http_query)
-
-from graphql.type.schema import GraphQLSchema
-
-from .render_graphiql import render_graphiql
-
-
-class GraphQLView(View):
- schema = None
- executor = None
- root_value = None
- pretty = False
- graphiql = False
- backend = None
- graphiql_version = None
- graphiql_template = None
- graphiql_html_title = None
- middleware = None
- batch = False
-
- methods = ['GET', 'POST', 'PUT', 'DELETE']
-
- def __init__(self, **kwargs):
- super(GraphQLView, self).__init__()
- for key, value in kwargs.items():
- if hasattr(self, key):
- setattr(self, key, value)
-
- assert isinstance(self.schema, GraphQLSchema), 'A Schema is required to be provided to GraphQLView.'
-
- # noinspection PyUnusedLocal
- def get_root_value(self):
- return self.root_value
-
- def get_context_value(self):
- return request
-
- def get_middleware(self):
- return self.middleware
-
- def get_backend(self):
- return self.backend
-
- def get_executor(self):
- return self.executor
-
- def render_graphiql(self, params, result):
- return render_graphiql(
- params=params,
- result=result,
- graphiql_version=self.graphiql_version,
- graphiql_template=self.graphiql_template,
- graphiql_html_title=self.graphiql_html_title,
- )
-
- format_error = staticmethod(default_format_error)
- encode = staticmethod(json_encode)
-
- def dispatch_request(self):
- try:
- request_method = request.method.lower()
- data = self.parse_body()
-
- show_graphiql = request_method == 'get' and self.should_display_graphiql()
- catch = show_graphiql
-
- pretty = self.pretty or show_graphiql or request.args.get('pretty')
-
- extra_options = {}
- executor = self.get_executor()
- if executor:
- # We only include it optionally since
- # executor is not a valid argument in all backends
- extra_options['executor'] = executor
-
- execution_results, all_params = run_http_query(
- self.schema,
- request_method,
- data,
- query_data=request.args,
- batch_enabled=self.batch,
- catch=catch,
- backend=self.get_backend(),
-
- # Execute options
- root_value=self.get_root_value(),
- context_value=self.get_context_value(),
- middleware=self.get_middleware(),
- **extra_options
- )
- result, status_code = encode_execution_results(
- execution_results,
- is_batch=isinstance(data, list),
- format_error=self.format_error,
- encode=partial(self.encode, pretty=pretty)
- )
-
- if show_graphiql:
- return self.render_graphiql(
- params=all_params[0],
- result=result
- )
-
- return Response(
- result,
- status=status_code,
- content_type='application/json'
- )
-
- except HttpQueryError as e:
- return Response(
- self.encode({
- 'errors': [self.format_error(e)]
- }),
- status=e.status_code,
- headers=e.headers,
- content_type='application/json'
- )
-
- # Flask
- # noinspection PyBroadException
- def parse_body(self):
- # We use mimetype here since we don't need the other
- # information provided by content_type
- content_type = request.mimetype
- if content_type == 'application/graphql':
- return {'query': request.data.decode('utf8')}
-
- elif content_type == 'application/json':
- return load_json_body(request.data.decode('utf8'))
-
- elif content_type in ('application/x-www-form-urlencoded', 'multipart/form-data'):
- return request.form
-
- return {}
-
- def should_display_graphiql(self):
- if not self.graphiql or 'raw' in request.args:
- return False
-
- return self.request_wants_html()
-
- def request_wants_html(self):
- best = request.accept_mimetypes \
- .best_match(['application/json', 'text/html'])
- return best == 'text/html' and \
- request.accept_mimetypes[best] > \
- request.accept_mimetypes['application/json']
diff --git a/flask_graphql/render_graphiql.py b/flask_graphql/render_graphiql.py
deleted file mode 100644
index 6bfb2da..0000000
--- a/flask_graphql/render_graphiql.py
+++ /dev/null
@@ -1,138 +0,0 @@
-from flask import render_template_string
-
-GRAPHIQL_VERSION = '0.11.11'
-
-TEMPLATE = '''
-
-
-