How to receive JSON in a POST request in CherryPy?
Asked Answered
B

3

29

How to receive JSON from POST requests in CherryPy?

I've been to this page, and though it does a good job explaining the API, its parameters, and what it does; I can't seem to figure out how to use them to parse the incoming JSON into an object.

Here's what I have so far:



import cherrypy
import json

from web.models.card import card
from web.models.session import getSession
from web.controllers.error import formatEx, handle_error

class CardRequestHandler(object):

    @cherrypy.expose
    def update(self, **jsonText):
        db = getSession()
        result = {"operation" : "update", "result" : "success" }
        try:
            u = json.loads(jsonText)
            c = db.query(card).filter(card.id == u.id)
            c.name = u.name
            c.content = u.content
            rzSession.commit()
        except:
            result["result"] = { "exception" : formatEx() }
        return json.dumps(result)

And, here's my jquery call to make the post


function Update(el){
    el = jq(el); // makes sure that this is a jquery object

    var pc = el.parent().parent();
    pc = ToJSON(pc);

    //$.ajaxSetup({ scriptCharset : "utf-8" });
    $.post( "http://localhost/wsgi/raspberry/card/update", pc,
            function(data){
                alert("Hello Update Response: " + data);
            }, 
            "json");
}

function ToJSON(h){
    h = jq(h);
    return { 
        "id" : h.attr("id"), 
        "name" : h.get(0).innerText, 
        "content" : h.find(".Content").get(0).innerText
    };
}
Bushtit answered 18/9, 2010 at 22:31 Comment(0)
E
31

Working example:

import cherrypy
import simplejson

class Root(object):

    @cherrypy.expose
    def update(self):
        cl = cherrypy.request.headers['Content-Length']
        rawbody = cherrypy.request.body.read(int(cl))
        body = simplejson.loads(rawbody)
        # do_something_with(body)
        return "Updated %r." % (body,)

    @cherrypy.expose
    def index(self):
        return """
<html>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type='text/javascript'>
function Update() {
    $.ajax({
      type: 'POST',
      url: "update",
      contentType: "application/json",
      processData: false,
      data: $('#updatebox').val(),
      success: function(data) {alert(data);},
      dataType: "text"
    });
}
</script>
<body>
<input type='textbox' id='updatebox' value='{}' size='20' />
<input type='submit' value='Update' onClick='Update(); return false' />
</body>
</html>
"""

cherrypy.quickstart(Root())

The doc you linked to describes a couple of CherryPy Tools that are new in version 3.2. The json_in tool basically does the above, with some more rigor, and using the new body processing API in 3.2.

One important thing to note is that jQuery's post function doesn't seem to be able to send JSON (only receive it). The dataType argument specifies the type of data you expect the XmlHTTPRequest to receive, not the type it will send, and there doesn't seem to be an argument available for you to specify the type you want to send. Using ajax() instead allows you to specify that.

Erfurt answered 20/9, 2010 at 16:9 Comment(0)
L
49

Python

import cherrypy

class Root:

    @cherrypy.expose
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def my_route(self):

        result = {"operation": "request", "result": "success"}

        input_json = cherrypy.request.json
        value = input_json["my_key"]

        # Responses are serialized to JSON (because of the json_out decorator)
        return result

JavaScript

//assuming that you're using jQuery

var myObject = { "my_key": "my_value" };

$.ajax({
    type: "POST",
    url: "my_route",
    data: JSON.stringify(myObject),
    contentType: 'application/json',
    dataType: 'json',
    error: function() {
        alert("error");
    },
    success: function() {
        alert("success");
    }
});
Lukewarm answered 21/8, 2013 at 20:57 Comment(2)
cherrypy.request has no attribute jsonDanonorwegian
@Danonorwegian check that you have the @cherrypy.tools.json_in() decorator.Schafer
E
31

Working example:

import cherrypy
import simplejson

class Root(object):

    @cherrypy.expose
    def update(self):
        cl = cherrypy.request.headers['Content-Length']
        rawbody = cherrypy.request.body.read(int(cl))
        body = simplejson.loads(rawbody)
        # do_something_with(body)
        return "Updated %r." % (body,)

    @cherrypy.expose
    def index(self):
        return """
<html>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type='text/javascript'>
function Update() {
    $.ajax({
      type: 'POST',
      url: "update",
      contentType: "application/json",
      processData: false,
      data: $('#updatebox').val(),
      success: function(data) {alert(data);},
      dataType: "text"
    });
}
</script>
<body>
<input type='textbox' id='updatebox' value='{}' size='20' />
<input type='submit' value='Update' onClick='Update(); return false' />
</body>
</html>
"""

cherrypy.quickstart(Root())

The doc you linked to describes a couple of CherryPy Tools that are new in version 3.2. The json_in tool basically does the above, with some more rigor, and using the new body processing API in 3.2.

One important thing to note is that jQuery's post function doesn't seem to be able to send JSON (only receive it). The dataType argument specifies the type of data you expect the XmlHTTPRequest to receive, not the type it will send, and there doesn't seem to be an argument available for you to specify the type you want to send. Using ajax() instead allows you to specify that.

Erfurt answered 20/9, 2010 at 16:9 Comment(0)
C
0

I found the @cherrypy.tools.json_in() way not very clean since it forces you to use cherrypy.request.json. Instead, the following decorator tries to mimic GET parameters.

The following helps this.

NOTE: This assumes you want to return JSON:

def uses_json(func):

    @functools.wraps(func)
    @cherrypy.tools.accept(media="application/json")
    def wrapper(*args, **kwargs):

        cherrypy.serving.response.headers['Content-Type'] = "application/json"

        kwargs = dict(kwargs)

        try:
            body = cherrypy.request.body.read()
            kwargs.update(json.loads(body))
        except TypeError:
            pass

        return json.dumps(func(*args, **kwargs)).encode('utf8')

    return wrapper

example:

 {"foo": "bar"}

get's translated into

 class Root(object): 
     ...
 
     @cherrypy.expose
     @uses_json
     def endpoint(self, foo):
         ....
Coagulase answered 20/11, 2017 at 4:3 Comment(1)
This is actually quite an interesting approach. Could you explain a little about why you merge kwargs with json in response body? If everything is expected from json, what kind of parameters would come as kwargs?Distillate

© 2022 - 2024 — McMap. All rights reserved.