skip to Main Content

I’m implementing an API (proxy) that accepts incoming JSON POST data in Flask.
I need to process this JSON and after that send it on to a backend API, which was written in another language.

The JSON data will be sent by end-users, and they are used to sending this JSON data case-insensitive. This means that the incoming JSON data will sometimes have uppercase keys/nodes, sometimes lowercase, and sometimes maybe camelcase or pascalcase.

I’m using Flasks request.json to get the data from the request. It is parsed into a Python object, but this object will have case-sensitive keys and values. These will also be nested.

A specific example of how I currently get data is:

data['ORDERS']['authentication']['AccountToken']

But my users might POST:

{
    "Orders": {
        "Authentication": {
            "AccountToken": "C3485D7B" 
        },
    ...

Is there a way to get data['ORDERS']['authentication']['AccountToken'] in such a way that the complete path to that value is case-insensitive?
I understand I can check for each part of the path case-insensitive separately, but that requires a lot of overhead code to get to the right child-nodes.

I saw other solutions: Case insensitive dictionary

I have also tried using CaseInsensitiveDict from the requests library like this:
data = CaseInsensitiveDict(request.json), but that only makes the first level of the object case insensitive actually.

The problem with these solutions is that they deal with dicts, while the JSON data is a dict of objects that can be lists or other objects. The solutions provided don’t work recursively or only on Dicts.

Any help is appreciated.

2

Answers


  1. Do you have to keep the case that the users send you? If not, it’s always a good idea to sanitise your input to some standard format, rather than anticipating everything you could be sent. Rather than checking your path case-insensitively, you could convert all your keys to plain lowercase on input, eg:

    def make_all_keys_lowercase(d: dict) -> None:
        for k, v in list(d.items()):
            if type(v) == dict:
                make_all_keys_lowercase(d[k])
            d[k.lower()] = d.pop(k)
    

    Which doesn’t require a lot of boilerplate and lets you keep the same path internally.

    Login or Signup to reply.
  2. This function outputs a case insensitive dict, creating it recursively for every entry:

    from requests.structures import CaseInsensitiveDict
    
    def case_insensitive_copy(data):
        if not isinstance(data, dict):
           return data
        temp_dict = {}
        for key, value in data.items():
           temp_dict[key] = case_insensitive_copy(value)
        return CaseInsensitiveDict(temp_dict)
    
    d = { "Orders": {
        "Authentication": {
            "AccountToken": "C3485D7B"
             }
          }
        }
    
    d = case_insensitive_copy(d)
    print(d['ORDERS']['authentication']['AccountToken'])
    >>> C3485D7B
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search