The boto3 framework provides an easy-to-use programmatic interface to work with AWS Services and makes it easy to work with the JSON responses these services return. But it can get quite quirky when working with large and complex JSON responses. Learn how to fix this specific issue while working with the boto3 framework.
Contents
The Error
Let’s assume that you’re trying to invoke a Lambda function (Target) from another Lambda function (Caller) using boto3 client’s invoke
method. Let’s assume that the Target function returns the following JSON response.
#Called function (Target) return { 'statusCode': 200, 'body': { 'message' : 'Hello World!' } }
You try to access the returned response using this code:
#Calling function (Caller) message = response['Payload']['body']['message']
and you encounter this error:
{ "errorMessage": "'StreamingBody' object is not subscriptable", "errorType": "TypeError", "requestId": "1cba0dc1-1382-478d-9061-6a2959596a1b", "stackTrace": [ ] }
The Fix
If you need to parse and consume this JSON from the Caller function, you need to understand how the response is packaged and returned from the Target function by the boto3 framework. To understand how the response is returned, invoke the function and print the response
object.
lambda_client = boto3.client('lambda') response = lambda_client.invoke( FunctionName = 'arn:aws:lambda:us-east-1:000000000000:function:target_function', InvocationType = 'RequestResponse' ) print(response['Payload'])
You’ll see something similar to this:
{'ResponseMetadata': {'RequestId': '8e719177-508b-4bbc-88fa-400691cebe68', 'HTTPStatusCode': 200, 'HTTPHeaders': {'date': 'Sun, 12 Feb 2023 04:57:15 GMT', 'content-type': 'application/json', 'content-length': '55', 'connection': 'keep-alive', 'x-amzn-requestid': '8e719177-508b-4bbc-88fa-400691cebe68', 'x-amzn-remapped-content-length': '0', 'x-amz-executed-version': '$LATEST', 'x-amzn-trace-id': 'root=1-63e871ab-7737df4b541ec559279b5a5a;sampled=0'}, 'RetryAttempts': 0}, 'StatusCode': 200, 'ExecutedVersion': '$LATEST', 'Payload': <botocore.response.StreamingBody object at 0x7f0d77b82d30>}
Note how the Payload Element is returned as a StreamingBody
object. You should parse this and convert the stream object to a JSON object before you can start parsing it using the subscript notation. Change the code to this:
response_json = json.load(response['Payload']) message = response_json['body']['message'] #print(response_json)
You should now be able to successfully read and parse the response. If you wish to debug, uncomment line #3 to see the complete response as a JSON string. The json.load
method converts the stream object to a JSON object and then you can read the elements inside the JSON object.
If you found this article helpful and it solved your problem, then please leave a comment. Also, do not forget to share this blog with friends and coworkers.