Why can I not send a json HttpResponse with booleans?

Hello,

What I’m trying to do:
I am trying to return a json object in a HttpRespone’s body.
The dictionary should contain multiple keys with booleans, but Postman recieves an internal server error stating that:

Cannot send a Boolean object over HTTP as response[“test”].
You must return either Media, a string, or a JSON-compatible object (lists/dicts/strings/numbers/None).

Code Sample:

@anvil.server.http_endpoint("/test/",methods=["POST"])
def test(**args):
  return anvil.server.HttpResponse(status=200,body={"test":True})

Sending the booleans as string or sending the whole json object as string is not an option.

Is there something I am missing, or I am can not to send booleans in json at all?

Edit: note that the error came from Postman. So sending isn’t the problem. The problem is at the receiving end.

Postman’s list is clearly incomplete. JSON defines values “true” and “false” as booleans. See the railroad diagram on the linked page.

Until they fix that, however, it looks like you’ll have to comply with their limitations.

Interesting, since I have already worked with Postman with other api’s and I never ran into this issue.

Will have to dump my json as string then specify it as application/json in the header.

Anyways, thanks for the info.

@p.colbert I’m not sure it’s a Postman error. I was able to recreate with curl


I copied the code about but used a different API endpoint.
curl -X POST   {{hostname}}/_/api/boolean_test/  


Cannot send a Boolean object over HTTP as response["test"].
You must return either Media, a string, or a JSON-compatible object (lists/dicts/strings/numbers/None).

Hm. I was going on the original statement that it was Postman’s “internal server error”. If that statement is incorrect, then an Anvil error is more likely. Here we find a match to the error message:

I have no idea why booleans would be disallowed in any JSON structure. Perhaps some in-between software layer is failing to distinguish between bool (a subclass of int) and int?

FWIW Did a few tweaks … change code to return a dictionary and built a decorator to JSON encode any return values from a function.

Decorator

def jsonify(logger):
    def decorator(fn):
        @functools.wraps(fn)
        def wrapper(*args, **kwargs):
            try:
                args_repr = [repr(a) for a in args]
                kwargs_repr = ["{}={}".format(k, v) for k, v in kwargs.items()]
                signature = ", ".join(args_repr + kwargs_repr)
                logger.info('CALLING ' + fn.__name__ + ' ' + signature)
                return json.dumps(fn(*args, **kwargs))
            except Exception:
                logger.exception('call failed')
                raise
            finally:
                logger.info('EXITING ' + fn.__name__)

        return wrapper
    return decorator

Note, this decorator also add’s some logging, so every function call will get log statements similar to … for ENTRY / EXIT style logging.

2022-07-22 18:42:17,198 root            INFO    : CALLING boolean_test 
2022-07-22 18:42:17,198 root            INFO    : EXITING boolean_test

New Test Code …

@anvil.server.http_endpoint("/boolean_test/", methods=["POST"])
@jsonify(logger)
def api_boolean_test(**args):
    return boolean_test(**args)


@anvil.server.callable
def boolean_test(**args):
    return {"test": True}

Function boolean_test can be called from client code or uplink and return a dict aligned to pythonic expectations.

But if you want to use that function in the API, I added a wrapper function to associate the API endpoint (/boolean_test/) and used decorator to json.dumps() the results.

No technical reason for the breaking the callable and http_endpoint into two different functions, but stylistically I am leaning that way.

From the sounds of it, @adorjana.arpad already did this (json encode his dictionarys to and returns str) across the board for his app …

Anyhoo, seems like there is a bug with the JSON-Encoder in the guts of anvil.server.HttpResponse

From the text in the docs I would expect the simple dictionary {"test" : True} to be encoded auto-magically.


oh and re-running the new test code from command line with curl


curl -X POST  {{hostname}}/_/api/boolean_test/


{"test": true}%                                       

so json.dumps / jsonify the dict avoids this error.


@patricia @meredydd Maybe you can clarify. Should anvil.server.HttpResponse body attribute auto-magically json-encode a dict ?

1 Like