Re: POST JSON vs. urlencoded

"John P. Rouillard" <[email protected]>
Newsgroups gmane.comp.bug-tracking.roundup.devel
Message-ID <[email protected]>
Hi Ralf:

In message <[email protected]>,
Ralf Schlatterbeck writes:
>Until now I had tested POST to the REST API only with content-type
>application/x-www-form-urlencoded -- this works fine. Now I've started
>testing with application/json and I'm getting a traceback where a
>type-check on the id for a link fails in the rdbms backend with the
>message "link value must be String".

I am not seeing that. I haven't tested POST with anything more than
title and status. PATCH and PUT have more testing. Note ... is
https://rouilj.dynamic-dns.net.

I can reproduce with the following POST running under python2

$ curl -s -u demo:demo -X POST --header 'Content-Type: application/json' \
  --header "Accept: application/json" \
  ".../demo/rest/data/issue" \
  --data '{ "title": "let rest rule the day", "status": "1"}'
{
    "data": {
        "link": ".../demo/rest/data/issue/2238",
        "id": "2238"
}

where status is an id. If I remove status it works fine.

If I use python 3, it works fine.

>Now it turns out, the check there compares the value it gets to type('')
>but gets a unicode id from the REST API. The RDBMS backend (at least in
>Python2) should get UTF-8 encoded strings, not unicode. So my guess is
>that somewhere in the guts of the REST API there is a decode() step
>missing.

Try this patch:

diff -r 1b9ef04b9528 roundup/rest.py                                           
--- a/roundup/rest.py   Mon Apr 01 21:53:30 2019 -0400                         
+++ b/roundup/rest.py   Tue Apr 02 18:18:17 2019 -0400                         
@@ -33,7 +33,7 @@
 from roundup import hyperdb                                                   
 from roundup import date                                                      
 from roundup import actions                                                   
-from roundup.anypy.strings import bs2b, b2s                                   
+from roundup.anypy.strings import bs2b, b2s, u2s                              
 from roundup.exceptions import *                                              
 from roundup.cgi.exceptions import *                                          
                                                                               
@@ -1616,7 +1616,6 @@
         ''' Parse the json string into an internal dict. '''                  
         def raise_error_on_constant(x):                                       
             raise ValueError("Unacceptable number: %s"%x)                     
-                                                                              
         self.json_dict = json.loads(json_string,                              
                                     parse_constant = raise_error_on_constant)
         self.value = [ self.FsValue(index, self.json_dict[index]) for index i\
n self.json_dict.keys() ]                                                      
@@ -1624,8 +1623,14 @@
     class FsValue:                                                            
         '''Class that does nothing but response to a .value property '''      
         def __init__(self, name, val):                                        
-            self.name=name                                                    
-            self.value=val                                                    
+            import pdb; pdb.set_trace()                                       
+            self.name=u2s(name)                                               
+            if type(val) == str:                                              
+                self.value=u2s(val)                                           
+            elif type(val) == type([]):                                       
+                self.value = [ u2s(v) for v in val ]                          
+            else:                                                             
+                self.value = str(val)                                         
                                                                               
     def __getitem__(self, index):                                             
         '''Return an FsValue created from the value of self.json_dict[index]  

That seems to fix the issue for me. If you agree, I'll check in the
change.

>Example working POST (urlencoded) (deleted some headers):
>
>POST /job-log/rest/data/issue HTTP/1.1
>User-Agent: python-requests/2.12.4
>Content-Length: 179
>Content-Type: application/x-www-form-urlencoded
>
>status=waiting-for-confirmation&customer=1505609&demo_rq_id=4711081542421&title=Noch+ein+test&messages=228&priority=normal&salesperson=22&org_link=1&crm_requester=22&opportunity=1
>
>Exampe not-working POST (json) (deleted some headers):
>POST /job-log/rest/data/issue HTTP/1.1
>User-Agent: python-requests/2.12.4
>Content-Length: 233
>Content-Type: application/json
>
>{"status": "waiting-for-confirmation", "customer": "3", "demo_rq_id": "471108154242", "title": "Noch ein test", "messages": "228", "priority": "normal", "salesperson": "22", "org_link": "1", "crm_requester": "22", "opportunity": "1"}
>
>
>When using the python request library, reproducing this is simple:
>I prepare the value dictionary and the I either use
>
>session = requests.session()
>session.auth = (username, password)
>
>d = dict (...)
>
># for the urlencoded payload:
>r = session.post (url + 'issue', data = d)
>#for the JSON payload:
>r = session.post (url + 'issue', json = d)
>
>
>Did anyone already test modifying methods (POST, PUT, PATCH) with a json
>payload?
>
>John, how did you test so far?

$ curl -s -u demo:demo -X PATCH --header 'Content-Type: application/json' \
  --header "Accept: application/json" \
  ".../demo/rest/data/user/3" \
    --data '{ "address": "[email protected]", "@etag": "\"c377290f846236eb5482e168baa9779e\""}'
{
    "data": {
        "id": "3",
        "type": "user",
        "link": ".../demo/rest/data/user/3",
        "attribute": {
            "address": "[email protected]"
        }
    }
}

$ curl -s -u demo:demo -X PUT --header 'Content-Type: application/json' --header "Accept: application/json"    ".../demo/rest/data/user/3"    --data '{ "address": "[email protected]", "@etag": "\"7f4c93a1b4399238aa41b4a3c645bc7d\""}'
{
    "data": {
        "id": "3",
        "type": "user",
        "link": ".../demo/rest/data/user/3",
        "attribute": {
            "address": "[email protected]"
        }
    }
}

the above done with python 3 and they work with python2 below:.

$ curl -s -u demo:demo -X PUT --header 'Content-Type: application/json' --header "Accept: application/json"    ".../demo/rest/data/user/3"    --data '{ "address": "[email protected]", "@etag": "\"19ce875c0a0fbe42b444473f72f46f69\""}'
{
    "data": {
        "link": ".../demo/rest/data/user/3", 
        "type": "user", 
        "id": "3", 
        "attribute": {
            "address": "[email protected]"
        }
    }
}

$ curl -s -u demo:demo -X PATCH --header 'Content-Type: application/json' --header "Accept: application/json"    ".../demo/rest/data/user/3"    --data '{ "address": "[email protected]", "@etag": "\"8217954773bf530cc74d682e714d41a5\""}'
{
    "data": {
        "link": ".../demo/rest/data/user/3", 
        "type": "user", 
        "id": "3", 
        "attribute": {
            "address": "[email protected]"
        }
    }
}

But note I am not setting any id's. With python2 this works for me:

$ curl -s -u demo:demo -X PUT --header 'Content-Type: application/json' \
  --header "Accept: application/json" \
  ".../demo/rest/data/issue/27" \
   --data '{ "nosy": [ "1", "3" ], "@etag": "\"d771fec250476ac349e4b74cc6331609\""}'
{
    "data": {
        "link": ".../demo/rest/data/issue/27", 
        "type": "issue", 
        "id": "27", 
        "attribute": {
            "nosy": [
                "1", 
                "3"
            ]
        }
    }
}

similar with python 3. All the tests above were without the patch.

--
				-- rouilj
John Rouillard
===========================================================================
My employers don't acknowledge my existence much less my opinions.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.