graphene-gae icon indicating copy to clipboard operation
graphene-gae copied to clipboard

Passing query as JSON (for variables, etc.) seems broken

Open uebayasi opened this issue 7 years ago • 8 comments

I'm very new to this GraphQL world but my understanding of GraphQL is that, in order to pass variables or operation_name in addition to query, the body of POST has to be encoded in JSON. A GraphQL query HTML body, with a pair of query and variables, would look like:

{ "query": "...", "variables": "..." }

This does not seem to work with graphene-gae. I put many logging.warn()'s in _get_grapl_params() but could not understand the intent. If the said assumption that GraphQL query body is either raw GraphQL or JSON, this _get_grapl_params() would look like:

    def _get_grapl_params(self):
        try:
            (read body as JSON)
        except:
            (read body as raw GraphQL)

(I even have no idea why this handler has to be implemented in graphene-gae, not graphene.)

I'm trying to fix this myself, but I'm slow; new to Python, new to GraphQL, new to Web world. Feel free to beat me. ;)

uebayasi avatar Oct 28 '16 03:10 uebayasi

Probably checking Content-Type (either application/graphql or application/json) would be saner.

uebayasi avatar Oct 28 '16 04:10 uebayasi

hey @uebayasi , do _get_graphql_params starts with this code:

        try:
            request_data = self.request.json_body
            if isinstance(request_data, basestring):
                request_data = dict(query=request_data)
        except:
            request_data = {}

Meaning, if you send a JSON object ({ "query": "...", "variables": "..." }) it'll use that, and if you send a JSON string it'll treat is as the query.

The code that follows reads operation_name and variables from request_data. So if you send a POST request that looks like { "query": "...", "variables": "..." } GraphQLHandler should handle it properly. Are you having problems with such a request?

The reason this handler is implemented in graphene-gae and not graphene is that its written specifically for the Google AppEngine environment - using webapp2 which is GAE's web framework. The main graphene library should not depend on GAE specific code thats of no use to people on other platforms.

ekampf avatar Oct 28 '16 17:10 ekampf

Thanks for the quick reply!

Now I see the problem; self.request.json_body is failing for me. I grep -r'ed json_body under google-cloud-sdk/platform/google_appengine/lib/webapp2-* and got no result. There are references under other subdirectories but I have no idea of relevance.

json.loads(self.request.body) surely works and that's I'm using it for now.

This is google-cloud-sdk 132.0.0 (2016/10/19).

uebayasi avatar Oct 29 '16 02:10 uebayasi

In requests.py there's this code:

    def _json_body__get(self):
        """Access the body of the request as JSON"""
        return json.loads(self.body.decode(self.charset))

    def _json_body__set(self, value):
        self.body = json.dumps(value, separators=(',', ':')).encode(self.charset)

    def _json_body__del(self):
        del self.body

    json = json_body = property(_json_body__get, _json_body__set, _json_body__del)

So basically self.request.json_body is the same as doing json.loads(self.request.body.decode(self.charset))

ekampf avatar Oct 29 '16 03:10 ekampf

This is part of the webob 1.2.3 library that webapp2 depends on

ekampf avatar Oct 29 '16 03:10 ekampf

I see that webapp2-2.5.1 and webob-1.2.3 are used (imported) here. I can't figure out why those inherited methods are called.

I'll try to investigate this later, but I can't promise. Feeling like Python not being my friend. :(

uebayasi avatar Oct 29 '16 05:10 uebayasi

For some reasons the request object inherits class BaseRequest in webob-1.1.1/webob/request.py, where _json_body__get is not defined. webob-1.2.3's class BaseRequest does define it.

Obviously this problem is not relevant to graphene-gae. It is either google-gcloud-sdk or python2.7 or my local environment causing the oddity. Feel free to close this issue.

Fortunately my project is not really started yet. I'm considering to switch to something and stay away from Python if possible... :(

uebayasi avatar Oct 29 '16 10:10 uebayasi

I just ran into this issue on a fresh install of Google Cloud SDK. It seems that webob version 1.1 gets loaded even though 1.2 is available. I fixed it by specifying the newer webob in my app.yaml:

libraries:
- name: webob
  version: 1.2.3
- name: webapp2
  version: 2.5.2

nolanw avatar Feb 27 '17 21:02 nolanw