Python How to GET Image and then POST (via requests library) - python

I am using python to try and get an image from one API, and then post it to a separate API.
So far I have this code:
def create_item(token, user_id):
url = '<api_url_to_post_to>'
headers = {"Authorization": "Token {0}".format(token)}
image_url = '<some_random_image_url>'
image_obj = requests.get(image_url)
data = {
"image": image_obj.content
}
r = requests.post(url, headers=headers, files=data)
response = r.json()
print(response)
return response
The issue is that when I try to post it to the second API, I get a "File extension '' is not allowed." error. This is obviously a custom error message, but it signifies that there is something wrong with the file that I am posting.
Any suggestions on what I may be doing wrong?

Try specifying the file type, just image_obj.content is the raw binary image:
r = requests.post(
url,
headers=headers,
files={'image': ('my_image.jpg', image_obj.content, 'image/jpg')})
This should add the correct headers to the multipart boundary for the image.
If you don't know for sure the content type, you might actually get it from the headers of your previous response: image_obj.headers['Content-Type'] should be "image/jpg" but for a different image it might be "image/png".

It wants a file extension, I'd hazard a guess that image should be image.<SOME_FORMAT>.

Related

How change the encoding in POST method in CaseInsensitiveDict()?

First thank you for your time. I'm trying to do an insert using a Rest-API POST, I'm working with Python. Among my messages I have special characters that I want to keep in the destination, which by the way returns an error for them since by default the messages are in UTF-8, but I want them in "ISO-8859-1".
For this I have created the line: headers["Charset"] = "ISO-8859-1" . Python does not give me an error but I continue with the same problem.
The error is:
400 Client Error: Bad Request for url: https://api.example.com/
Here is my code:
import requests
from requests.structures import CaseInsensitiveDict
url = 'https://api.example.com/'
headers = CaseInsensitiveDict()
headers["Accept"] = "application/json"
headers["Authorization"] = "Bearer "
headers["Content-Type"] = "application/json"
headers["Charset"] = "ISO-8859-1"
collet_x = df_spark.collect()
for row in collet_x:
#insert
resp = requests.post(url, headers=headers, data=row['JSON'])
v_respuesta = resp.text
print(resp.status_code)
print(v_respuesta)
How else can I change the encoding?
From already thank you very much.
Regards

Change project Avatar with Azure DevOPS API 6.0-preview.1 and python

I'm trying to change the Project Avatar/picture for a project in Azure DevOps with the api.
For that I'm using a python script. The api docu states that the picture has to be send as a byte array. But the type is descripted as string array. So for me it sounds like the byte array has to be converted to a string and then send in a json.
In python this looks like this:
url = f'https://dev.azure.com/{organization}/_apis/projects/{project_id}/avatar?api-version=6.0-preview.1 '
with open(project_picture_path, "rb") as image:
image_array = []
while byte := image.read(1):
image_array.append(byte)
image_array = str(image_array)
json1 = json.dumps({"image": image_array})
headers = {'Content-type': 'application/json'}
r = requests.put(url, data=json1, auth=auth, headers=headers)
print(r.status_code)
When I send this put request to the server it just responds with a 204 http code, which is odd in it self because the docu states it should respond with a 200.
When I go to the project page in DevOps the picture has indeed changed, but not to my specified picture. Instead from the default to what seems to be a placeholder image.
You can see a comparison here
I don't have any idea what went wrong here.
Did anyone else tried doing that?
After lots of testing I found a solution.
The api wants to get the bytes as int values so we have to convert them to int like this:
with open(project_picture_path, "rb") as image:
image_array = []
while byte := image.read(1):
image_array.append(int.from_bytes(byte, 'big'))
json1 = json.dumps({"image": image_array})
headers = {'Content-type': 'application/json'}
r = requests.put(url, data=json1, auth=auth, headers=headers)
print(r.status_code)
This way the api still gives a 204 response code but the picture changes correctly. This should definitely be changed in the docs.

Python requests upload file with POST

I'm currently struggling with a really simple problem, but cant spot the problem in detail.
I want to upload a file via requests.post, the current approach looks kinda like:
fin = open(f"{path_dtl}{filename}.dtl", "rb")
files = {"file": fin}
headers = CaseInsensitiveDict()
headers["Authorization"] = f"Bearer {auth_token}"
headers["Content-Type"] = "application/octet-stream"
headers["Content-Disposition"] = f"form-data;filename ='{filename}.dtl'"
upload_dtl = requests.post(url, headers=headers, files=files)
The result is a {'error': 'Invalid Media Type/Mime Type'} response. Is there a need to open a .dtl file in different manner? The usage of a request with this configuration via Postman works fine so I guess I missed a silly mistake. Thanks in advance.
UPDATE
Alright... for anyone interested. The cause of the issue was the default key-value "file" in files = {"file": fin} is different for my API. Following workaround fixed my issue.
with open(f"{path_dtl}{filename}.dtl", "rb") as f: files = f.read()
...
upload_dtl = requests.post(url, headers=headers, files=files)
Have you tried specifying a type? You can do so like this:
files = {'file': ('aaa.csv', open('aaa.csv', 'rb'),'text/csv')}

requests.post returns isSuccess:false even though Postman returns true

I am trying to post some information into an API based on their recommended format. When I use Postman( tool to test APIs), I see that the response has the isSuccess flag set to true. However, when I write the same code in Python using the requests library, I get the isSuccess flag as false
As mentioned about, I verified the headers and the json data object, both are the same yet the results defer
import requests
data = {"AccountNumber":"100007777",
"ActivityID":"78",
"ActivityDT":"2019-08-07 12:00:00",
"ActivityValue":"1"
}
url = "http://<IP>/<API_PATH>"
headers = {
"X-Tenant":"Default",
"Content-Type":"application/json"
}
response = requests.post(url,data=data, headers = headers)
print(response.content)
This code should successfully post the data and I should get a isSuccess:true in my response variable.
Can anyone help me figure out what might be wrong?
Can you try to change;
response = requests.post(url,data=data, headers = headers)
to;
response = requests.post(url,json=data, headers = headers)
or;
response = requests.post(url,body=data, headers = headers)

How can I post a PDF to AWS lambda

I have AWS Lambda set up.
def lambda_handler(event, context):
return {
'statusCode': 200,
'body': json.dumps(event)
}
I would like to POST in a PDF file so that I can operate on it in my lambda function.
Here is my POST code
import requests
headers = {
'X-API-KEY':'1234',
'Content-type': 'multipart/form-data'}
files = {
'document': open('my.pdf', 'rb')
}
r = requests.post(url, files=files, headers=headers)
display(r)
display(r.text)
I am getting the error:
<Response [400]>
'{"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
How can I POST over my PDF and be able to properly send over my PDF and access it in Lambda?
Note:
I am successful if I do this:
payload = '{"key1": "val1","key2": 22,"key3": 15,"key4": "val4"}'
r = requests.post(url = URL, data=payload, headers=HEADERS)
It is just the PDF part which I can't get
I figured it out. Took me a ton of time but I think I got it. Essentially it's all about encoding and decoding as bytes. Didn't have to touch the API Gateway at all.
Request:
HEADERS = {'X-API-KEY': '12345'}
data = '{"body" : "%s"}' % base64.b64encode(open(path, 'rb').read())
r = requests.post(url, data=data, headers=HEADERS)
In lambda
from io import BytesIO
def lambda_handler(event, context):
pdf64 = event["body"]
# Need this line as it does 'b'b'pdfdatacontent'.
pdf64 = pdf64[2:].encode('utf-8')
buffer = BytesIO()
content = base64.b64decode(pdf64)
buffer.write(content)
I found this worked quite well for me:
Request
import requests
file_loc = 'path/to/test.pdf'
data = open(file_loc,'rb').read() #this is a bytes object
r = requests.post(url, data=data)
r.ok #returns True (also a good idea to check r.text
#one-liner
requests.post(url, data=open(file_loc,'rb').read())
Lambda - Python3.8
import io, base64
body = event["body"]
attachment = base64.b64decode(body.encode()) #this is a bytes object
buff = io.BytesIO(attachment) #this is now useable - read/write etc.
#one-liner
buff = io.BytesIO(base64.b64decode(event["body"].encode()))
Not quite sure why, but for me base64 encoding (even with urlsafe) in the original request corrupted the file and it was no longer recognised as a PDF in Lambda, so the OP's answer didn't work for me.

Categories

Resources