Curl command to Python request - doesn't work - python

I'm trying to convert the following curl (which works fine) to Python code:
curl -X POST https://api.example.com/c \
-H 'Authorization: Bearer {token}' \
-H 'content-type: multipart/form-data' \
-F 'attachment[c_id]=1111' \
-F 'attachment[file]=#file.png'
I've tried two different options:
Option #1:
import requests
headers = {
'Authorization': 'Bearer {token}',
'content-type': 'multipart/form-data',
}
files = {
'attachment[c_id]': (None, '1111'),
'attachment[file]': ('file.png', open('file.png', 'rb')),
}
response = requests.post('https://api.example.com/c',
headers=headers, files=files)
Option #2:
import requests
from requests_toolbelt.multipart.encoder import MultipartEncoder
headers = {
'Authorization': 'Bearer {token}',
'content-type': 'multipart/form-data',
}
multipart_data = MultipartEncoder(
fields=(
('attachment[file]', open('file.png', 'rb')),
('attachment[c_id]', '1111')
))
response = requests.post('https://api.example.com/c',
headers=headers, data=multipart_data)
Both options failed with the following error:
requests.exceptions.ConnectionError: ('Connection aborted.', BrokenPipeError(32, 'Broken pipe'))
So, it means that Python code works in a different way because curl works just fine.
I've tried https://curl.trillworks.com/ - it didn't help, unfortunately.
How can I do the same on Python?

I've just found the solution - the problem was in the Content-Type headers.
Important: when we use the "files" parameter for request, we shouldn't use the Content-Type header, requests will set it on his own (the size of payload should be in this header, and requests library will add this information automatically).
The following code works just fine:
import requests
headers = {
'Authorization': 'Bearer {token}',
}
files = (
('attachment[c_id]', (None, '1111')),
('attachment[file]', ('file.png', open('file.png', 'rb')))
)
response = requests.post('https://api.example.com/c',
headers=headers, files=files)

Related

Failed to read the request form. Missing content-type boundary after convert request from curl or postman during send zip file

I would like to send a zip file using Python Requests. How to correct my code to send the zip file correctly?
My Curl request working fine and returns 200
curl -X 'POST' \
'https://xxx/bulk' \
-H 'accept: application/json;odata.metadata=minimal;odata.streaming=true'
-H 'Authorization: Basic xxx'
-H 'Content-Type: multipart/form-data'
-F 'File=#/home/dominik/ok/batch.zip;type=application/x-zip-compressed'
My Postman request returns 200. But the Python code from the Postman generator doesn't work.
Python code
headers = {
'accept': 'application/json;odata.metadata=minimal;odata.streaming=true',
'Content-Type': 'multipart/form-data',
'Authorization' : 'Basic xxx'}
def send_zip(zip_path, url, headers):
start_time = time.perf_counter()
zip_to_send = {'file': ('batch.zip', open(zip_path, 'rb'), 'application/x-zip-compressed')}
response = requests.request('POST', url, headers=headers, files=zip_to_send)
print(response.text, response.status_code)
end_time = time.perf_counter()
total_time = end_time - start_time
print(f'Total time to send zip: {total_time}')
my code returns
Failed to read the request form. Missing content-type boundary
I know about curlconverter but it returns the code with the file error
headers = {'accept': 'application/json;odata.metadata=minimal;odata.streaming=true',
'Authorization': 'Basic xxx,
# requests won't add a boundary if this header is set when you pass files=
# 'Content-Type': 'multipart/form-data',
}
fils = {'File': open('/hoome/ok/batch.zip;type=application/x-zip-compressed', 'rb'),}
response = requests.post('https://xxx/bulk', headers=headers, files=files, )

Python post request throwing 400 'Bad Request' error with requests library but works with cURL

I have a script that calls a POST endpoint but getting a 400 error. Meanwhile, the corresponding cURL request is successful.
First, here is the cURL:
curl -X 'POST' \
'http://localhost:8080/api/predict?Key=123testkey' \
-H 'accept: application/json' \
-H 'Content-Type: multipart/form-data' \
-F 'file=#156ac81cde4b3f22faa4055b53867f38.jpg;type=image/jpeg'
And translated to requests:
import requests
url = 'http://localhost:8080/api/predict?Key=123testkey'
headers = {
'accept': 'application/json',
'Content-Type': 'multipart/form-data',
}
params = {'Key' : '123testkey'}
files = {'image': open('156ac81cde4b3f22faa4055b53867f38.jpg', 'rb')}
response = requests.post(url, files=files, params=params, headers=headers)
Have also tried using a URL that does not include the key, since the key is already specified in params:
import requests
url = 'http://localhost:8080/api/predict'
headers = {
'accept': 'application/json',
'Content-Type': 'multipart/form-data',
}
params = {'Key' : '123testkey'}
files = {'image': open('156ac81cde4b3f22faa4055b53867f38.jpg', 'rb')}
response = requests.post(url, files=files, params=params, headers=headers)
I thought this should be simple but I consistently get the 400 error with requests no matter what I try. Any suggestions?
Edit: have also tried 'image/jpeg' instead of 'image' to no avail.
Edit: replacing the "image" key with "file" unfortunately didn't work either
Edit: It works in postman desktop just fine, and generates the following code. However, this code also throws an error.
The generated code from postman:
import requests
url = "http://localhost:8080/api/predict?Key=123test"
payload={}
files=[
('file',('images19.jpg',open('156ac81cde4b3f22faa4055b53867f38.jpg','rb'),'image/jpeg'))
]
headers = {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data'
}
response = requests.request("POST", url, headers=headers, data=payload, files=files)
print(response.text)
And the error from the previously generated code from postman:
{"detail":"There was an error parsing the body"}
Any help figuring out what is going on would be much appreciated!
Your issue is in the variable files you need to add with the key 'file' instead of 'image' that's the difference between your curl and your python code, also remove the header because when you pass the file parameter the request set the proper header for send files. for example:
import requests
url = 'http://localhost:8080/api/predict?Key=123testkey'
params = {'Key' : '123testkey'}
files = {'file': open('156ac81cde4b3f22faa4055b53867f38.jpg', 'rb')}
response = requests.post(url, files=files, params=params)

Post request to specific API with file

I'm trying to make a post request to API:
access_token = '71e89e8af02206575b3b4ae80bf35b6386fe3085af3d4085cbc7b43505084482'
url_base = "https://dev-100-api.huntflow.ru/"
url_resume = '{0}account/6/upload'.format(url_base)
headers_resume = {
'Content-Type': 'multipart/form-data',
'X-File-Parse': 'true',
'Authorization': 'Bearer {0}'.format(access_token),
}
files = {
'file': open('Глибин Виталий Николаевич.doc', 'rb'),
}
resume1 = requests.post(url_resume, headers=headers_resume, files=files)
print(resume1.text)
And output is: {"errors": [{"type": "server_error"}]}
The documentation says:
POST /account/{account_id}/upload
To upload a file send a request multipart/form-data with a file in parameter file.
To make sure that the file will be processed by the system of field recognition, one has to pass a header X-File-Parse: true. In this case the response will contain the fields text, photo, fields.
Example request:
curl -X POST \
-H "Content-Type: multipart/form-data" \
-H "X-File-Parse: true" \
-H "Authorization: Bearer <token>" \
-F "file=#resume.pdf" \
https://api.huntflow.ru/account/<account_id>/upload
Help me, please! What's wrong?
After some research I found this issue related to the same website you're trying to send file to it
The solution is something like follows:
import requests
import os
import mimetypes
token = "71e89e8af02206575b3b4ae80bf35b6386fe3085af3d4085cbc7b43505084482"
url = "https://dev-100-api.huntflow.ru/account/6/upload"
def upload_file(name, content):
mimetypes.init()
ext_data = os.path.splitext(name)
if len(ext_data) > 1:
mime_type = mimetypes.types_map.get(ext_data[len(ext_data) - 1]) or 'application/zip'
else:
mime_type = 'application/zip'
headers = {
'Authorization': 'Bearer {}'.format(token),
'User-Agent': 'App/1.0 (eeee#eeee.ru)',
}
r = requests.request(
'POST',
url,
files={'file': (name, content, mime_type)},
headers=headers,
)
return r.json()
print(upload_file("test.txt", "text/plain"))
I got the following response:
{'name': 'test.txt', 'url': 'https://dev-100-store.huntflow.ru/uploads/named/z/q/j/zqj0jf98dud8grbazjleyjy3ii4wrsah.txt/test.txt?s=z-pORM3y1qUVU4XhbsHKBg&e=1589632103', 'content_type': 'text/plain', 'id': 58}

Converting CURL command to Python with requests

I want to use the requests library in Python to make a POST request.
But the API I'm trying to use uses curl to make the request and I don't know how to convert that.
This is the curl command:
curl -X POST "https://api/recognize?secret_key=abc" -H "accept: application/json" -H "Content-Type: multipart/form-data" -F "image=#/path/to/image.jpg;type=image/jpeg"
For the moment I'm just using a URL instead of the image itself as a workaround.
Code:
params = (
('image_url', '2015-BMW-320djpg'),
('secret_key', 'abc'),
)
response = requests.post('https://api/recognize_url', params=params)
As far as I'm aware there's no "cURL -> Requests" translator, but it should be fairly easy to translate that one request (and requests like it) to use the requests module.
files = {'image': open('/path/to/image.jpg', 'rb')}
params = {'secret_key': 'abc'}
headers = {'accept': 'application/json'}
response = requests.post(url, files=files, params=params, headers=headers)
First, paste your command into curlconverter.com/python/ and it will convert it to
import requests
headers = {
'accept': 'application/json',
}
params = {
'secret_key': 'abc',
}
files = {
'image': open('/path/to/image.jpg;type=image/jpeg', 'rb'),
}
response = requests.post('https://api/recognize', params=params, headers=headers, files=files)
Then, the 'image': open('/path/to/image.jpg;type=image/jpeg', 'rb'), line is wrong because the ;type=image/jpeg is not part of the file path to your image. To correct it, you need to read the curl documentation for the -F flag and the Requests documentation for the files= parameter (or just the Advanced Usage page) to know that you need to change it to
files = {
'image': ('image.jpg', open('/path/to/image.jpg', 'rb'), 'image/jpeg'),
}

Calling Curl API on Python

I want to call CURL API on python.
curl -X POST -H "Authorization:Token 00d2e3a10c82420414b2d36d28fb5afc2cd8e8a5" \
-H "Content-Type: application/json" \
-d '{"module_id":"[MODULE_ID]", "text": "example text"}' \
-D - \
https://api.tocall.com/
I used requests module for making request and json module for converting object to string. But I'm getting 404.
Where am I wrong?
import requests
import json
headers = {
'Authorization': 'Token 00d2e3a10c82420414b2d36d28fb5afc2cd8e8a5',
'Content-Type': 'application/json',
}
url = "https://api.tocall.com/"
data = '{"module_id":"[MODULE_ID]", "text": "example text"}'
response= requests.post(url, data=json.dumps(data), headers=headers)
print(response.status_code)
You are encoding your data as JSON twice. json.dumps() takes an object and converts to JSON. In this case, you are converting a string to JSON. This should work better:
import requests
headers = {
'Authorization': 'Token 00d2e3a10c82420414b2d36d28fb5afc2cd8e8a5',
}
url = "https://api.tocall.com/"
data = {"module_id":"[MODULE_ID]", "text": "example text"}
response= requests.post(url, json=data, headers=headers)
print(response.status_code)
If it still doesn't work and you need more help, you should include real details about your API so we can reproduce the issue.
json.dumps turns a Python dict to a string, but your data is already a string. The easiest thing to do is write data as a dict then use json.dumps on that.
Add the Host header, so that the final server knows on which virtual host to route the request,
Change:
headers = {
'Authorization': 'Token 00d2e3a10c82420414b2d36d28fb5afc2cd8e8a5',
'Content-Type': 'application/json',
}
For:
headers = {
'Authorization': 'Token 00d2e3a10c82420414b2d36d28fb5afc2cd8e8a5',
'Content-Type': 'application/json',
'Host' : 'api.tocall.com'
}
I think this will fix your issue. Eventually you might want to update the default headers, not craft your own ones. Try to use the session features of requests to perform consistent queries.
Note: as stated by other answers, you have other JSON encoding issues, but that's not the reason why you are getting 404.

Categories