How to return error messages in JSON with Bottle HTTPError?

11.6k views Asked by At

I have a bottle server that returns HTTPErrors as such:

return HTTPError(400, "Object already exists with that name")

When I receive this response in the browser, I'd like to be able to pick out the error message given. As it is right now I can see the error message in the response's responseText field, but it's buried in an HTML string that I'd rather not parse if I don't have to.

Is there any way I can specifically set the error message in Bottle so I can pick it out in JSON in the browser?

3

There are 3 answers

0
dreyescat On BEST ANSWER

HTTPError uses a predefined HTML template to build the body of the response. Instead of using HTTPError you can use response with the appropriate status code and body.

import json
from bottle import run, route, response

@route('/text')
def get_text():
    response.status = 400
    return 'Object already exists with that name'

@route('/json')
def get_json():
    response.status = 400
    response.content_type = 'application/json'
    return json.dumps({'error': 'Object already exists with that name'})

# Start bottle server.
run(host='0.0.0.0', port=8070, debug=True)
0
ara.hayrabedian On

only just started working with bottle but would recommend something more along the lines of:

import json
from bottle import route, response, error, abort

@route('/text')
def get_text():
    abort(400, 'object already exists with that name')

# note you can add in whatever other error numbers
# you want, haven't found a catch-all yet
# may also be @application.error(400)
@error(400) #might be @application.error in some usages i think.
def json_error(error):
    """for some reason bottle don't deal with 
    dicts returned the same way it does in view methods.
    """
    error_data = {
        'error_message': error.body
    }
    response.content_type = 'application/json'
    return json.dumps(error_data)

didn't run the above so expect mistakes, but you get the gist.

1
Michael On

I was looking for a similar way, to handle all error messages as JSON responses. The problem with the above solution is, that they don't do it in a nice and generic way, i.e. to handle any possible popping error, not just a defined 400 etc. Imho the cleanest solution is, to override the default error, and then work with a custom bottle object:

class JSONErrorBottle(bottle.Bottle):
    def default_error_handler(self, res):
        bottle.response.content_type = 'application/json'
        return json.dumps(dict(error=res.body, status_code=res.status_code))

The passed res argument has some more attributes about the thrown error, which may be returned, see the code for the default template for that. Especially .status, .exception and .traceback seem relevant.