Send image file to AWS Lambda Function - python

I'm trying to send one image to my Lambda Function using Python just to test for one project, but Postman is giving me one error and I don't know how to solve it.
My code is simply to detect if I have some data in the key "image" and return some message. I'm using Postman to send the POST request, I clicked in the Body tab, selected the form-data option and I wrote image for the key and selected the image file from my computer (the image size is 27 kb). This is the code in my Lambda Function:
def lambda_handler(event, context):
if event['image']:
return {
"Message": 'Everything went ok'
}
And this is the error message that I'm receiving from Postman:
{ "message": "Could not parse request body into json: Unexpected
character ('-' (code 45)) in numeric value: expected digit (0-9) to
follow minus sign, for valid numeric value\n at [Source:
(byte[])"----------------------------137965576541301454606184\r\nContent-Disposition: form-data; name="image"; filename="TestImage.png"\r\nContent-Type:
image/png\r\n\r\n�PNG\r\n\n ... }

To solve that problem, I needed to set my Camera to convert the image to base64 and then upload it to the server.
In the server, I convert it again and then work with it as I want. Base64 is a group of binary-to-text encoding schemes that represent binary data in an ASCII string format by translating it into a radix-64 representation.
So, you will convert your image to string and then sending it, it was the best way that I found to upload my images.

I was struggling with this. I was using Postman, getting UnidentifiedImageError. The below worked.
Posting the Image:
data = open('x.jpg','rb').read()
data = base64.b64encode(data).decode("utf8")
r = requests.post('url',data=data)
Processing on the function side
def lambda_handler(event, context):
image_bytes = event['body'].encode('utf-8')
img_b64dec = base64.b64decode(image_bytes)
img_byteIO = BytesIO(img_b64dec)
image = Image.open(img_byteIO)

Related

How to send json formatted messages to Slack through Cloud functions?

I am trying to send a json formatted message to Slack through a Cloud function using slack_sdk, if I send it like this (not formatted) it works.
client = WebClient(token='xoxb-25.......')
try:
response = client.chat_postMessage(channel='#random', text=DICTIONARY)
I found the documentation on Slack that chat_postMessage supports sending json formats by setting the HTTP headers:
Content-type: application/json
Authorization: Bearer xoxb-25xxxxxxx-xxxx
How would that work applied in my code above? I want to send a big python dictionary and would like to receive it formatted in the Slack channel. I tried adding it in multiple ways and deployment fails.
This is the documentation: https://api.slack.com/web
Bit late, but I hope this can help others who stumble upon this issue in the future.
I think that you've misunderstood the documentation. The JSON support allows for accepting POST message bodies in JSON format, as only application/x-www-form-urlencoded format was supported earlier. Read more here.
To answer your question, you can try to send the dictionary by formatting it or in a code block as Slack API supports markdown.
Reference- Slack Text Formatting.
Sample Code-
from slack_sdk import WebClient
import json
client = WebClient(token="xoxb........-")
json_message = {
"title": "Tom Sawyer",
"author": "Twain, Mark",
"year_written": 1862,
"edition": "Random House",
"price": 7.75
}
# format and send as a text block
formatted_text = f"```{json.dumps(json_message, indent = 2)}```"
client.chat_postMessage(channel = "#general", text = formatted_text)
# format and send as a code block
formatted_code_block = json.dumps(json_message, indent = 2)
client.chat_postMessage(channel = "#general", text = formatted_code_block)
Output-

Validating webhook with sha256 hmac using PHP and Python

I am working with webhooks from Bold Commerce, which are validated using a hash of the timestamp and the body of the webhook, with a secret key as the signing key. The headers from the webhook looks like this :
X-Bold-Signature: 06cc9aab9fd856bdc326f21d54a23e62441adb5966182e784db47ab4f2568231
timestamp: 1556410547
Content-Type: application/json
charset: utf-8
According to their documentation, the hash is built like so (in PHP):
$now = time(); // current unix timestamp
$json = json_encode($payload, JSON_FORCE_OBJECT);
$signature = hash_hmac('sha256', $now.'.'.$json, $signingKey);
I am trying to recreate the same hash using python, and I am always getting the wrong value for the hash. I've tried several combinations, with and without base64 encoding. In python3, a bytes object is expected for the hmac, so I need to encode everything before I can compare it. At this point my code looks like so :
json_loaded = json.loads(request.body)
json_dumped = json.dumps(json_loaded)
# if I dont load and then dump the json, the message has escaped \n characters in it
message = timestamp + '.' + json_dumped
# => 1556410547.{"event_type" : "order.created", "date": "2020-06-08".....}
hash = hmac.new(secret.encode(), message.encode(), hashlib.sha256)
hex_digest = hash.hexdigest()
# => 3e4520c869552a282ed29b6523eecbd591fc19d1a3f9e4933e03ae8ce3f77bd4
# hmac_to_verify = 06cc9aab9fd856bdc326f21d54a23e62441adb5966182e784db47ab4f2568231
return hmac.compare_digest(hex_digest, hmac_to_verify)
Im not sure what I am doing wrong. For the other webhooks I am validating, I used base64 encoding, but it seems like here, that hasnt been used on the PHP side. I am not so familiar with PHP so maybe there is something I've missed in how they built the orginal hash. There could be complications coming from the fact that I have to convert back and forth between byte arrays and strings, maybe I am using the wrong encoding for that ? Please someone help, I feel like I've tried every combination and am at a loss.
EDIT : Tried this solution by leaving the body without encoding it in json and it still fails :
print(type(timestamp)
# => <class 'str'>
print(type(body))
# => <class 'bytes'>
# cant concatenate bytes to string...
message = timestamp.encode('utf-8') + b'.' + body
# => b'1556410547.{\n "event_type": "order.created",\n "event_time": "2020-06-08 11:16:04",\n ...
hash = hmac.new(secret.encode(), message, hashlib.sha256)
hex_digest = hash.hexdigest()
# ...etc
EDIT EDIT :
Actually it is working in production ! Thanks to the solution described above (concatenating everything as bytes). My Postman request with the faked webhook was still failing, but that's probably because of how I copied and pasted the webhook data from my heroku logs :) .

How to receive a file with an Aws Lambda (python)

I'm trying to figure out how to receive a file sent by a browser through an API call in Python.
The web client is allowed to send any types of files (let's say .txt, .docx, .xlsx, ...). I don't know if I should use binary or not.
The idea was to save the file after on S3. Now I know it's possible to use js libraries like Aws Amplify and generate a temporary url but i'm not too interested in that solution.
Any help appreciated, I've searched extensively a solution in Python but i can't find anything actually working !
My API is private and i'm using serverless to deploy.
files_post:
handler: post/post.post
events:
- http:
path: files
method: post
cors: true
authorizer:
name: authorizer
arn: ${cf:lCognito.CognitoUserPoolMyUserPool}
EDIT
I have a half solution that works for text files but doesn't for PDF, XLSX, or images, if someone had i'd be super happy
from cgi import parse_header, parse_multipart
from io import BytesIO
import json
def post(event, context):
print event['queryStringParameters']['filename']
c_type, c_data = parse_header(event['headers']['content-type'])
c_data['boundary'] = bytes(c_data['boundary']).encode("utf-8")
body_file = BytesIO(bytes(event['body']).encode("utf-8"))
form_data = parse_multipart(body_file, c_data)
s3 = boto3.resource('s3')
object = s3.Object('storage', event['queryStringParameters']['filename'])
object.put(Body=form_data['upload'][0])
You are using API Gateway so your lambda event will map to something like this (from Amazon Docs):
{
"resource": "Resource path",
"path": "Path parameter",
"httpMethod": "Incoming request's method name"
"headers": {String containing incoming request headers}
"multiValueHeaders": {List of strings containing incoming request headers}
"queryStringParameters": {query string parameters }
"multiValueQueryStringParameters": {List of query string parameters}
"pathParameters": {path parameters}
"stageVariables": {Applicable stage variables}
"requestContext": {Request context, including authorizer-returned key-value pairs}
"body": "A JSON string of the request payload."
"isBase64Encoded": "A boolean flag to indicate if the applicable request payload is Base64-encode"
}
You can pass the file as a base64 value in the body and decode it in your lambda function. Take the following Python snippet
def lambda_handler(event, context):
data = json.loads(event['body'])
# Let's say we user a regular <input type='file' name='uploaded_file'/>
encoded_file = data['uploaded_file']
decoded_file = base64.decodestring(encoded_file)
# now save it to S3

Send MySQL blob content as a json response

I have the following code of a GET method which takes a photo which is stored in a blob type field in MySql and return. I want to return it to the client inside a JSON string in a type it can display the image in an angularjs application.
def GET(self,r):
user_data = CC.get_data(query) # holds the content of the blob field.
print type(user_data) # prints <type 'str'>
data = {'name': 'test',
'photo': user_data}
return json.dump(data)
This gives,
UnicodeDecodeError: 'utf8' codec can't decode byte 0x89 in position 0:
invalid start byte
I have found in some websites its better to send as photo as byte array.
Im using web.py python framework.
whats the best way to do this?
To prevent data loss, the best thing you can do to send binary data is encode as base64.
import base64
def GET(self,r):
user_data = CC.get_data(query) # holds the content of the blob field.
data = {'name': 'test',
'photo': base64.b64encode(user_data)}
return json.dump(data)
However, sending binary data over JSON is really not recommended, specially in web. You can send a URL to download the photo, for example.
First how to work with blob:
http://www.mysqltutorial.org/python-mysql-blob/
To send your image to your template:
def imageResponseView(...) .... return response
bind url to this view
show image using <img src = "//url_to_that_view" />
From: I have an image's HTTPResponse. How do I display it in a Django template?

Microsoft Translator gives HTTP Error 400 only with certain strings

I am translating a large number of strings and using urllib2 to send requests to the API. My program will run fine, but I always get HTTP Error 400 when translating certain strings in particular. Each request I make is exactly the same, except for the text parameter, so I think it must be the text somehow causing the request to be malformed. Here are two strings that I know of that always cause this error:
#monaeltahawy hatla2eh fel jym bytmrn wla 3arf en fe 7aga bt7sl :d
and
#yaratambash ta3aly a3zemek 3l fetar
for example.
I know for certain that it isn't the "#" character causing the error, or the fact that "#" is at the front of the string. The API has processed strings with these attributes just fine before.
It also is not the nonsense words in these strings causing issues, because the API has processed nonsense words fine before as well. It just returns the same string that I sent to it.
Here is the code where the error seems to be coming from:
tweet = tweet.encode("utf-8")
to = "en"
translate_params = { 'text' : tweet, 'to' : to }
request = urllib2.Request('http://api.microsofttranslator.com/v2/Http.svc/Translate?' + urllib.urlencode(translate_params))
request.add_header('Authorization', 'Bearer '+ self.access_token)
response = urllib2.urlopen(request)
# Removes XML tags to return only the translated text
response_text = ET.fromstring(response.read())
response_text = ET.tostring(response_text, encoding = 'utf8', method = 'text')
return response_text
I am running Python 2.7 in Eclipse 4.3.2.
Any insight or suggestions would be very much appreciated.

Categories

Resources