In Python, is there a way to check if a string is valid JSON before trying to parse it?
For example working with things like the Facebook Graph API, sometimes it returns JSON, sometimes it could return an image file.
In Python, is there a way to check if a string is valid JSON before trying to parse it?
For example working with things like the Facebook Graph API, sometimes it returns JSON, sometimes it could return an image file.
You can try to do json.loads(), which will throw a ValueError if the string you pass can't be decoded as JSON.
In general, the "Pythonic" philosophy for this kind of situation is called EAFP, for Easier to Ask for Forgiveness than Permission.
loads in the except clause?10 is a valid JSON number value.import json def is_json(myjson): try: json.loads(myjson) except ValueError as e: return False return True Which prints:
print is_json("{}") #prints True print is_json("{asdf}") #prints False print is_json('{ "age":100}') #prints True print is_json("{'age':100 }") #prints False print is_json("{\"age\":100 }") #prints True print is_json('{"age":100 }') #prints True print is_json('{"foo":[5,6.8],"foo":"bar"}') #prints True Convert a JSON string to a Python dictionary:
import json mydict = json.loads('{"foo":"bar"}') print(mydict['foo']) #prints bar mylist = json.loads("[5,6,7]") print(mylist) [5, 6, 7] Convert a python object to JSON string:
foo = {} foo['gummy'] = 'bear' print(json.dumps(foo)) #prints {"gummy": "bear"} If you want access to low-level parsing, don't roll your own, use an existing library: http://www.json.org/
Great tutorial on python JSON module: https://pymotw.com/2/json/
sudo cpan JSON::XS echo '{"foo":[5,6.8],"foo":"bar" bar}' > myjson.json json_xs -t none < myjson.json Prints:
, or } expected while parsing object/hash, at character offset 28 (before "bar} at /usr/local/bin/json_xs line 183, <STDIN> line 1. json_xs is capable of syntax checking, parsing, prittifying, encoding, decoding and more:
del json_object once validated?try. #StopCanaryAbuseI would say parsing it is the only way you can really entirely tell. Exception will be raised by python's json.loads() function (almost certainly) if not the correct format. However, the the purposes of your example you can probably just check the first couple of non-whitespace characters...
I'm not familiar with the JSON that facebook sends back, but most JSON strings from web apps will start with a open square [ or curly { bracket. No images formats I know of start with those characters.
Conversely if you know what image formats might show up, you can check the start of the string for their signatures to identify images, and assume you have JSON if it's not an image.
Another simple hack to identify a graphic, rather than a text string, in the case you're looking for a graphic, is just to test for non-ASCII characters in the first couple of dozen characters of the string (assuming the JSON is ASCII).
I also used json.loads() to check if a string is a valid JSON, however I also needed to check if it is complex data structure or not. I did not want to save to the db a simple string or an integer for example... These are also valid JSON, but sometimes must be filter as well:
"\"valid json\"""1""3.14"My solution is here:
def is_json(string: str, is_complex: bool = False) -> bool: """ Return True if the given string is in valid JSON format, else return False. Example usage ------------- >>> is_json("1") # True because this is a valid JSON string True >>> is_json("1", True) # return False because this is a simple data structure (int) False :param string: :param is_complex: bool; If true also checked for complex data structure :return: bool """ try: valid_json = json.loads(string) if is_complex and type(valid_json) in [int, str, float, bool]: return False except ValueError: return False return True An effective, and reliable way to check for valid JSON. If the 'get' accessor does't throw an AttributeError then the JSON is valid.
import json valid_json = {'type': 'doc', 'version': 1, 'content': [{'type': 'paragraph', 'content': [{'text': 'Request for widget', 'type': 'text'}]}]} invalid_json = 'opo' def check_json(p, attr): doc = json.loads(json.dumps(p)) try: doc.get(attr) # we don't care if the value exists. Only that 'get()' is accessible return True except AttributeError: return False To use, we call the function and look for a key.
# Valid JSON print(check_json(valid_json, 'type')) Returns 'True'
# Invalid JSON / Key not found print(check_json(invalid_json, 'type')) Returns 'False'
get() returns None, not raises AttributeError. Did you mean to use doc[attr]? Or except ValueError instead?dict(), and that json.loads did not throw ValueError / TypeError. In other words, json.loads should be in the try body, as answered before ... 'opo' is still "valid JSON" since plain strings are still JSON. Better example - onecompiler.com/python/3yywagm8hI came up with an generic, interesting solution to this problem:
class SafeInvocator(object): def __init__(self, module): self._module = module def _safe(self, func): def inner(*args, **kwargs): try: return func(*args, **kwargs) except: return None return inner def __getattr__(self, item): obj = getattr(self.module, item) return self._safe(obj) if hasattr(obj, '__call__') else obj and you can use it like so:
safe_json = SafeInvocator(json) text = "{'foo':'bar'}" item = safe_json.loads(text) if item: # do something except clause may hide any serious exception. Catching exceptions must be as restrictive as possible.In my opinion, JSONDecodeError is much better option than ValueError.
Can do something like:
def jsn_check(jsn): try: in_jsn = json.loads(jsn) except (json.decoder.JSONDecodeError) as errh: return False return True Example:
import json jsn = """{ "value": 30, "type": "Tip 3, "targetModule": "Target 3", "version": 0, "systemId": 3} """ def jsn_check(jsn): try: in_jsn = json.loads(jsn) except (json.decoder.JSONDecodeError) as errh: return False return True print(jsn_check(jsn)) Output:
False Much simple in try block. You can then validate if the body is a valid JSON
async def get_body(request: Request): try: body = await request.json() except: body = await request.body() return body