zopefoundation / zope.publisher

Map requests from HTTP/WebDAV clients, web browsers, XML-RPC and FTP clients onto Python objects
Other
3 stars 12 forks source link

request POST JSON data is not handled as expected #68

Open petschki opened 2 years ago

petschki commented 2 years ago

What I did:

I sent an XHR call to zope like this:

const resp = await fetch("@@backend", {
    headers: {
        "Content-Type": "application/json",
    },
    method: "POST",
    body: JSON.stringify({
        id: "some_id",
        _authenticator: "some_authenticator",
    }),
});

What I expect to happen:

If I want to read the request in @@backend browser view I expect:

self.request.form = {
    "id": "some_id",
    "_authenticator": "some_authenticator",
}

What actually happened:

You have to extract the body data manually via:

form_data = json.loads(self.request["BODY"])

What version of Python and Zope/Addons I am using:

python: 3.9 Zope: master Plone: 6.0-dev

d-maurer commented 2 years ago

Peter Mathis wrote at 2022-6-2 02:52 -0700:

I sent an XHR call to zope like this:

const resp = await fetch("@@backend", {
   headers: {
       "Content-Type": "application/json",
   },
   method: "POST",
   body: JSON.stringify({
       id: "some_id",
       _authenticator: "some_authenticator",
   }),
});
...
### What I expect to happen:

If I want to read the request in `@@backend` browser view I expect:

self.request.form = { "id": "some_id", "_authenticator": "some_authenticator", }

### What actually happened:

You have to extract the body data manually via:

form_data = json.loads(self.request["BODY"])

Zope currently looks at content-type only in very rare cases: only to check for XML-RPC requests.

I would not be happy to support application/json in the way you suggest: it works only when the body represents a structure (then there are names to bind to); it does not work for e.g. a string or an array (no names to bind to).

I suggest, you use instead the :json type converter. With this, your example could look like: await fetch("@@backend?params:json=" + JSON.stringify({...}) and you would get the JSON decoded value in request["params"]. A similar approach would work for POST requests.

I believe that I already have seen a PR supporting the :json type converter: it might already be available.

Should I be wrong, "https://github.com/zopefoundation/Zope/pull/648" contains (among other things) such support. It has a good chance to arrive in Zope 6.

mgedmin commented 2 years ago

-1 for reusing request.form for this.

+1 for introducing a new request.json.