Pylons controller with both html and json output

We're all using ajax these days and one of the simple uses of ajax is to update or add some HTML content to a page. What often happens is that the same data is often display in a url/page of its own. So you might have a url /job/list and then you might want to pull a list of jobs onto a page via ajax. So my goal is to be able to reuse controllers to provide details for ajax calls, calls from automated scripts, and whole pages. The trouble with this is that the @jsonify decorator in Pylons is pretty basic. It just sets the content type header to application/json and takes whatever you return and tries to jsonify it for you.

That's great, but I can't reuse that controller to send HTML output any more. So I set out to figure out how the decorator works and create one that works more like I wish.

The first thing in setting this up was to look at how to structure any ajax output. I can't stand the urls you hit via ajax that just dump out some content, outputs some string, and makes you have to look up every controller in order to figure out just what you're getting back.

I prefer to use a structured format back. So what parts do we need. Really, just a few things. Your ajax library will tell you if there's an error such as a timeout, 404, etc. It won't tell you if you make a call to a controller and don't have perimission, or maybe the controller couldn't complete the requested action. So the first thing we need is some value of success in our request.

The second component is feedback as to why the success came back. If the controller returns a lack of success we'll want to know why. Maybe it is successful, but we need some note about the process along the way. We need a standard message we can send back.

Finally, we might want to return some sort of data back. This could be anything from a json dump of the object requested to actual html output we want to use.

So that leaves us with a definition [sourcecode lang="javascript"] {'success': true, 'message': 'Yay, we did it', 'payload': {'id': 10, 'name': 'Bob'}} [/sourcecode]

I want to enforace that any ajax controller will output something in format. It makes it much easier to write effective DRY javascript that can handle this and really leaves us open to handle about anything we need.

So my json decorator is going to have to make sure that if the user requests a json response, that it gets all this info. If the user requests an html response, it'll just return the generated template html.

By copying parts of the @jsonify and the @validate decorators I came up with something that adds a self.json to the controller method. In here we setup our json response parts.

Finally, we catch if this is a json request. If so, return our dumped self.json instance. Otherwise, return the html the controller sends back. If the controller is returning rendered html and is a json request, then we stick that into the payload as payload.html

So take a peek at my decorator code and the JSONResponse object that it uses. Let me know what you think and any suggestions. It's my first venture into the world of Python decorators.

@mijson decorator Gist

Sample Controller [sourcecode lang="python"]

@myjson() def pause(self, id): result = SomeObj.pause()

if self.accepts_json(): if result: self.json.success = True self.json.message = 'Paused' else: self.json.success = False self.json.message = 'Failed'

self.json.payload['job_id'] = id

return '<h1>Result was: %s</h1>' % message

#Response: # {'success': true, # 'message': 'Paused', # 'payload': {'html': '<h1>Result was: Paused</h1>'}} [/sourcecode]