I am trying to hit an API endpoint using python requests. I have been unable to successfully send the body of the request except when using cURL. Here is the cURL command that succeeds:
curl --location --request POST '<api endpoint url>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'obj={"login":"<email>","pword":"<password>"}'
Using python requests like this returns an error from the API because of the body of the request:
payload = 'obj={"login":"<email>","pword":"<password>"}'
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
response = requests.post(url, headers=headers, data=payload)
print(response.text)
I also tried requests.request("POST") but got the same results.
Your data is URL encoded as you can see in the curl Content-Type header, so you have to provide the data in an URL encoded format, not JSON.
Use the following instead. requests will set the Content-Type header to application/x-www-form-urlencoded automatically. It will also take care of the URL encoding.
data = {"login": "<email>", "pword": "<password>"}
response = requests.post(url, data=data)
Related
I am connecting through an API to receive data. From the website API documentation, the instructions use either two CURL methods to connect the API; however, I need to connect using python.
1st Method
Curl Example
curl -d '' -X POST 'https://api.bcda.cms.gov/auth/token' \
-H "accept: application/json" \
-H "authorization: Basic <Client_Secret>"
My Python Conversion:
import requests
import json
url = 'https://api.bcda.cms.gov/auth/token'
headers = {"accept": "application/json", "authorization": 'Basic',
'<API_Key>': '<API_Secret>'}
r = requests.post(url = url, data ={}, headers = headers)
print(r)
2nd Method Curl
curl -d '' -X POST 'https://api.bcda.cms.gov/auth/token' \
--user <Client_Key>:<Client_Secret> \
-H "accept: application/json"
My 2nd Python conversion code:
import requests
import json
url = 'https://api.bcda.cms.gov/auth/token'
user = {"<Client_Key>":"<Client_Secret>", "accept": "application/json"}
r = requests.post(url = url, headers = user)
print(r)
I am receiving a 403 connection error, meaning "response status code indicates that the server understands the request but refuses to authorize it."
You should use auth parameter and not headers to convert --user option
headers = {'accept': 'application/json'}
r = requests.post(url=url, headers=headers, auth=(client_key, client_secret))
I have the following curl command
curl -X POST "http://localhost:5000/api/v1/image/cad1b12e-c374-4d46-b43b-3ddbe7d683c4" -H "accept: application/json" -H "Content-Type: multipart/form-data" -F "file=#tests/test.jpg;type=image/jpeg"
I am trying to construct a pytest function with the same behavior that the command above but I am not getting the exact result, the pytest function is the following
url = "http://localhost:5000/api/v1/image/cad1b12e-c374-4d46-b43b-3ddbe7d683c4"
payload={}
files=[('file',('test.png',open('./tests/test.png','rb'),'image/png'))]
headers = {
'accept': 'application/json',
'Content-Type': 'multipart/form-data'
}
response = requests.request("POST", url, headers=headers, data=payload, files=files)
Short answer:
Don't specify a Content-Type in the headers dictionary, when providing a files argument to the requests.request method.
Longer answer
I tried to test that functionality to my own Flask upload script.
This worked when removing 'Content-Type': 'multipart/form-data' form the headers dictionary, otherwise the response was 400 bad request (see response.content)
I noted that after making the request, and inspecting response.request.headers I could see that
when specifying that header it was part of the request, as-is:
'Content-Type': 'multipart/form-data'
however when not specifying it requests automatically generates the header with a boundary, and the request succeeded:
'Content-Type': 'multipart/form-data; boundary=1beba22d28ce1e2cdcd76d253f8ef1fe'
Also:
To find the headers sent from curl, either by using the trace method or if you have access to the server, printing request.headers within the upload route, you can see that the curl command automatically appends a boundary to the header, even when the flag -H "Content-Type: multipart/form-data" is provided:
Content-Type: multipart/form-data; boundary=------------------------c263b5b9297c78d3
The same can be observed via the Network tab in your browser dev-tools, when uploading via an HTML form with enctype="multipart/form-data" set as an attribute.
I had always thought that manually adding 'Content-Type:':'multipart/form-data' to the headers dict was required, but it appears when using the the files argument to requests.request method, this is automatically generated with the boundary.
In fact the requests docs make no mention of setting this header yourself.
How can I convert this CURL PUT request to python requests:
The curl is
curl -X PUT "https://example.com" -H "accept: application/json" -H "Content-Type: application/json-patch+json" -d "{ \"userName\": \"exampleuser\", \"password\": \"examplepass\"}"
Currently got
headers = {"accept": "application/json",
"Content-Type": "application/json-patch+json"}
data = {'\"userName\"': '\"exampleuser\"',
'\"password\"': '\"examplepass\"'}
response = requests.put(url=url, data=data, headers=headers)
print(response)
Currently getting a 401 response. Unfortunately, the curl converter does not recognise it.
In bash, you escaped the quotes of the json
In Python, you shouldn't need to
data = {'userName' : 'exampleuser',
'password': 'examplepass'}
Then, you're sending json, so do json=data instead of data=data
When using the shell, I can successfully create a new user by running
curl --user administrator:pasword "Content-Type: application/json" https://localhost:8080/midpoint/ws/rest/users -d #user.json
However when I try to do the same thing in python using requests, I get a 200 response and no user is created.
This is the script I am using:
import requests
headers = {
'Content-Type': 'application/json',
}
data = open('user.json')
response = requests.post('https://localhost:8080/midpoint/ws/rest/users', headers=headers, data=data, auth=('Administrator', 'password'))
print(response)
To me they look the same. What is different in the python request that is stopping the user from being created?
I compare the post date with curl and python requests.And i found the difference.
CURL: {"user" : "hero","pd":30}
Requests: pd=30&user=hero
Then this is my test.
import requests
import json
headers = {
'Content-Type': 'application/json',
}
with open('user.json') as j:
data = json.load(j)
response = requests.post('http://127.0.0.1:8080',
headers=headers,
json = data,
auth=('Administrator', 'password'))
print(response.headers)
I think using json = data would work as well, but I was finally successful using json dumps: data=json.dumps(data)
I have a curl request as below:
curl -X POST \
https://example.com \
-H 'Content-Type: multipart/form-data' \
--form-string 'message=<messageML>Hello world!</messageML>'
How do i pass --form-string data in python request?
Thanks!
Use the files parameter to post your data, example:
import requests
url = 'https://httpbin.org/anything'
data = {'message':'<messageML>Hello world!</messageML>'}
r = requests.post(url, files=data)
print(r.text)
You don't have to use headers because 'multipart/form-data' is the default 'Content-Type' header when posting files.