Próbuję napisać bezsernalizowany tylny koniec dla aplikacji z AWS Lambda i uruchomię w błąd w tytule. Błąd występuje podczas testowania za pomocą integracji proxy API Gateway, ale funkcja działa dobrze po przetestowaniu w konsoli Lambda.

Oto błąd:

{  
   "errorMessage":"string indices must be integers",
   "errorType":"TypeError",
   "stackTrace":[  
      [  
         "/var/task/auth_login.py",
         17,
         "lambda_handler",
         "response = get_user(payload)"
      ],
      [  
         "/var/task/shifty_utils/__init__.py",
         22,
         "get_user",
         "table = dynamo.Table(user['company'] + '_users')"
      ]
   ]
}

Oto kontekst, w którym występuje:

def lambda_handler(event, context):
    payload = event['body']
    response = get_user(payload)

def get_user(user):
    try:
        table = dynamo.Table(user['company'] + '_users')
        response = table.get_item(
            Key={
                'userId': user['userId'],
                'position': user['position']
            }
        )
    except ClientError as e:
        print(e.response['Error']['Message'])
        return {'message': e.response['Error']['Message']}
    else:
        return response

Zasadniczo integracja proxy wydaje się czytać w obiekcie zdarzeń jako sformatowany ciąg JSON, w przeciwieństwie do dyktatu, ale tutaj dzieje się, jeśli dostosuję mój kod dla tego:

{  
   "errorMessage":"the JSON object must be str, bytes or bytearray, not 'dict'",
   "errorType":"TypeError",
   "stackTrace":[  
      [  
         "/var/task/auth_login.py",
         15,
         "lambda_handler",
         "payload = json.loads(event)"
      ],
      [  
         "/var/lang/lib/python3.6/json/__init__.py",
         348,
         "loads",
         "'not {!r}'.format(s.__class__.__name__))"
      ]
   ]
}

Nie mogę wygrać. Każda pomoc jest doceniana.

4
Phito 24 czerwiec 2017, 19:16

3 odpowiedzi

Najlepsza odpowiedź

Zidentyfikowałeś problem. Jednak próbujesz przekonwertować dict do dict.

Oto, co masz:

json.loads(event) # event is a dict

Część ciała, gdy słusznie zidentyfikowano, jest to, co jest wsiadanie jako str.

To właśnie powinieneś mieć:

json.loads(event['body'])

Jeszcze jednym krokiem jest uczynienie go klientem-agnostycznym.

if isinstance(event['body'], (unicode, str)):
    body = json.loads(event['body'])
9
Oluwafemi Sule 24 czerwiec 2017, 16:39

Podczas radzenia sobie z JSON, Python zapewnia 2 funkcje STD:

https://docs.Python.org/3/library/json.html#json.dumps.

Serializuj OBJ do JSON Sorfatted Str za pomocą tej tabeli konwersji. Argumenty mają takie samo znaczenie jak w Dump ().

https://docs.python.org/3/library/json.html#json.loads.

Deserialize S (Str, Bajty lub ByteArray Instancja zawierająca dokument JSON) do obiektu Pythona przy użyciu tej tabeli konwersji.

To, czego potrzebujesz tutaj jest najnowsze:

import json
payload = json.loads(event['body']

{{X0}.

1
user3682983 24 czerwiec 2017, 16:43

Dzieje się tak, ponieważ event['body'] nie jest dict, ale str. (Pobiegłem do tego problemu podczas dekodowania zdarzenia wywołanego SQS)

W przypadku, gdy ktoś wpadł w problem, gdy wartość json.loads(event['body']) nie jest ponownie dict ale str, oto rozwiązanie, które dekoduje str, aby rekurencyjnie rekurencyjnie.

import json

def to_dict(obj : object) -> dict:
    """ Serialize Object to Dictionary Recursively

    Arguments:
        obj {object} -- string, list, or dictionary to be serialize

    Returns:
        dict -- Serialized Dictionary
    """

    if isinstance(obj, dict):
        data = {}
        for k, v in obj.items():
            data[k] = to_dict(v)
        return data

    elif hasattr(obj, "_ast"):
        return to_dict(obj._ast())

    elif hasattr(obj, "__iter__") and not isinstance(obj, str):
        return [to_dict(v) for v in obj]

    elif hasattr(obj, "__dict__"):
        data = {key : to_dict(value) for key, value in obj.__dict__.items() if 
                  not callable(value) and not key.startswith('_')}

    elif isinstance(obj, str):
        try:
            data = {}
            obj = json.loads(obj)
            for k, v in obj.items():
                data[k] = to_dict(v)
                return data
        except:
            return obj
    else:
        return obj

Przykładowe zastosowanie:

test = {'Records': ['{"s3": "{\\"bucket\\": \\"bucketname\\"}"}', '{"s3": "{\\"bucket\\": \\"bucketname\\"}"}']}

print(to_dict(test)['Records'][0]['s3']['bucket'])

To powinno drukować "BucketName".

2
Pete Morris 4 grudzień 2018, 06:39