Ok, so here's what I've ended up doing. I created my own version of jsonify which simply passes a JSONEncoder sublcass to simplejson.dump's cls kw argument as so:
@decorator
def jsonify(func, *args, **kwargs):
pylons = get_pylons(args)
pylons.response.headers['Content-Type'] = 'application/json'
data = func(*args, **kwargs)
return json.dumps(data, cls=JSONEncoder)
Now, the above decorator will set the Content-Type header to application/json so long as the status int is 200. If an error code (e.g., 400, 401, 403, 404) is returned from one of my actions, then Pylons overrides my content type to text/html; charset=utf8. I don't want that because I include JSON error objects in the body of my responses (I don't know if that's intrinsically a bad idea, but that's what I want to do, so anyways...)
My hacky way of forcing this to happen is to create a piece of middleware to do it for me, sticking it in config/middleware.py (cf. Chapter 16, 'Changing the Status and Headers' of the Pylons Book). (If there's a better way to do this, please let me know). Here it is:
class HTML2JSONContentType(object):
"""Brute force text/html Content-Type in response to application/json.
Take that Pylons!
"""
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
def custom_start_response(status, headers, exc_info=None):
if dict(headers)['Content-Type'] == 'text/html; charset=utf-8':
newHeaders = dict(headers)
newHeaders['Content-Type'] = 'application/json'
headers = newHeaders.items()
return start_response(status, headers, exc_info)
return
self.app(environ, custom_start_response)
... and in config/middleware.py after the SessionMiddleware I have:
app = HTML2JSONContentType(app)
I haven't yet tested how this "solution" interacts with FileApp's setting of the content type. We'll see...