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

Added the ability to specify the JSON encoder #25

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
7 changes: 4 additions & 3 deletions flask_graphql/graphqlview.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class GraphQLView(View):
graphiql_template = None
middleware = None
batch = False
json_encoder = None
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this also include a json_decoder member? Roughly equivalent change with the json.loads -> self.json_decoder(…).decode(s) a couple places below.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completely agree, I've just updated the branch with json_decoder support.


methods = ['GET', 'POST', 'PUT', 'DELETE']

Expand Down Expand Up @@ -142,10 +143,10 @@ def get_response(self, request, data, show_graphiql=False):
def json_encode(self, request, d, show_graphiql=False):
pretty = self.pretty or show_graphiql or request.args.get('pretty')
if not pretty:
return json.dumps(d, separators=(',', ':'))
return json.dumps(d, separators=(',', ':'), cls=self.json_encoder)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to continue using json.dumps here rather than the encoder directly?

return self.json_encoder(separators=(',' ':')).encode(d)

I believe they're functionally equivalent but the .encode() route reduces the dependency on the builtin json module, since there are several json libraries that could be reasonably used: http://artem.krylysov.com/blog/2015/09/29/benchmark-python-json-libraries/

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not an expert on json encoding/decoding in Python. What you've said sounds great but I'd rather leave this to someone in a better position to comment.


return json.dumps(d, sort_keys=True,
indent=2, separators=(',', ': '))
return json.dumps(d, sort_keys=True, indent=2,
separators=(',', ': '), cls=self.json_encoder)

# noinspection PyBroadException
def parse_body(self, request):
Expand Down
6 changes: 6 additions & 0 deletions tests/encoder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from json import JSONEncoder


class TestJSONEncoder(JSONEncoder):
def encode(self, o):
return 'TESTSTRING'
13 changes: 11 additions & 2 deletions tests/test_graphqlview.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from urllib.parse import urlencode

from .app import create_app
from .encoder import TestJSONEncoder
from flask import url_for


Expand Down Expand Up @@ -500,8 +501,8 @@ def test_batch_supports_post_json_query_with_json_variables(client):
'payload': { 'data': {'test': "Hello Dolly"} },
'status': 200,
}]


@pytest.mark.parametrize('app', [create_app(batch=True)])
def test_batch_allows_post_with_operation_name(client):
response = client.post(
Expand Down Expand Up @@ -532,3 +533,11 @@ def test_batch_allows_post_with_operation_name(client):
},
'status': 200,
}]


@pytest.mark.parametrize('app', [create_app(json_encoder=TestJSONEncoder)])
def test_custom_encoder(client):
response = client.get(url_string(query='{test}'))

# TestJSONEncoder just encodes everything to 'TESTSTRING'
assert response.data.decode() == 'TESTSTRING'