I am trying to call the shiftplanning API with the following code:
import requests
url= "https://humanity.com/api/"
payload = {"key": "keyvalue", "request": { "module": "staff.login", "method": "GET","username": "myusername", "password": "mypassword"}}"
headers = {
'content-type': "application/x-www-form-urlencoded",
'cache-control': "no-cache",
}
r = requests.post(url, data = payload
, headers= headers)
r.text
I used Postman to test the api beforehand and it worked fine. The payload in the Postman code creator, however, looks like this:
payload = "data={\r\n \"key\": \"keyvalue\",\r\n \"request\": {\r\n \"module\": \"staff.login\",\r\n \"method\": \"GET\",\r\n \"username\": \"myusername\",\r\n \"password\": \mypassword\"\r\n }\r\n}"
I assume, that the payload variable actually needs to be formatted as a string, as the doc at shiftplanning api says:
Remember that any data passed to the API is to be formatted as JSON, and its string value needs to be sent via the POST HTTP request method all as the post variable 'data' (Checkout the 9th line from an example below). Also Content-Type needs to be set to application/x-www-form-urlencoded.
However, no matter what I do, I always get the html of the api as a return, not the json response to my http request.
Using
r.json()
doesn't do anything, except raising an error, due to the returned html.
I also tried using
json = payload
in the post request, that didn't change anything either.`
Any help and explanation is appreciated. I'd really like to understand what I am doing wrong, as it seems to be pretty straightforward to execute.
Change content-type in headers to application/json if you want json response. Postman automatically sets that header for you but you need to set it in your Python code.
Related
I was able to get the auth token from the login api but I am trying to use it to query the events api and I am getting a 401 Client Error: Unauthorized for url error message. Here is a snippet of my code:
def action():
data = {
'login': 'xxxxxxxxx',
'password': 'xxxxx',
}
urllib3.disable_warnings()
try:
timestamp = int(round(time.time() * 1000))
print(timestamp)
r = requests.post(
'https://host:port/www/core-service/rest/LoginService/login', data=data, verify=False)
login_request = untangle.parse(r.text)
user_session_id = login_request.ns3_loginResponse.ns3_return.cdata
print(user_session_id)
response = requests.post(
'https://host:port/detect-api/rest/v1/events/retrieve',
headers={
"Accept": "application/json",
"Authorization": user_session_id,
"Content-Type": "application/json"
},
data={
"ids": 79745681,
"startTime": timestamp,
"endTime": timestamp
},
verify=False)
print(response)
res = untangle.parse(response.text)
print(res)
Can somebody please point out what is wrong with my code?
You didn't add link to API so I only guess what can make problem.
If you set "Content-Type": "application/json" then it can means you want to send json data.
So you should use
post(..., json=...)
instead of
post(..., data=...).
Using data= you send it as form, not json. And header Content-Type can't change it.
And when you use json= then you don't have to add "Content-Type": "application/json" because requests will add it automatically.
EDIT:
In comment you said that you have working curl command (but you didn't said it in question, and you didn't show curl in question)
On page https://curl.trillworks.com you can convert curl to Python (and few other languages) and mostly it works correctly.
BTW:
If you use postman for tests then it has also function to generate code for curl, Python and many other languages.
You didn't show link to API documentation but often API documentation has examples for curl and sometimes even for Python.
First time trying to extract data via an API. I'm getting stuck with how to pass the raw data. I have been able to get it to work in postman but I can't quite figure it out with Python.
I've been getting this error:
{'fault': {'faultstring': 'JSONThreatProtection[JSON-Threat-Protection-1]: Execution failed. reason: Expecting { or [ at line 1', 'detail': {'errorcode': 'steps.jsonthreatprotection.ExecutionFailed'}}}
I'm pretty sure its the data portion that is wrong but I haven't been able to figure out if it's just a syntax error or something bigger that I'm missing.
My code as follows:
import requests
import json
url = "https://url/customers/shipmentstatus"
headers = {
"Authorization": "Bearer TOKEN",
"Content-Type": "application/json"
}
data = {
"Id": [
"AZ1234"
]
}
response = requests.post(url, headers=headers, data=data)
print(response.json())
Your code posts the data as form encoded data, not as JSON. That's because you use the data parameter to supply the payload. To fix, encode the data as JSON using json.dumps():
response = requests.post(url, headers=headers, data=json.dumps(data))
But a better way is to pass the data to requests using the json parameter:
response = requests.post(url, headers=headers, json=data)
Using the json parameter is easier and it will also add the Content-Type: application/json header for you.
I am trying to upload several files and some metadata through a POST to a server API using python and requests. I want to use the multipart/form-data type and not encode the data.
I've followed the steps according to tutorials and the requests documentation, but run into several issues:
import requests
data = {
"key1": "value1",
"key2": "value2"
}
files = {
"image": open('image.jpg', 'rb')
}
headers = {
"accept": "*/*",
"Authorization": "Bearer " + token
"Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryzqgQ4h5D6Zi8"
}
r = requests.post(url, files=files, data=data, headers=headers, verify=False)
print(r.status_code, r.text)
This gets me a 400 and the error:
"Failed to read the request form. Multipart body length limit 16384 exceeded."
I read that what might help is to leave the Content-Type to requests and it will figure it out.
Without the Content-Type declaration I still get a 400 and a the text back:
file is required
Now this might be a server-side issue (which I have no see over), since it demands multipart/form-data, but I suppose requests deals with the correct identification?
So far I'm out of luck, does anyone have an idea how to solve this?
EDIT: still don't know what exactly causes the issue, but found a workaround:
added all the data directly to the URL string
eliminated all the headers but the necessary Authorization token
It seems to me that requests is able to do a lot of the heavy lifting and too much declarations get in the way (?).
I have a python post request to a server where my flask app is hosted. It works fine and I am able to get the desired data.
But I want to test the API using POSTMAN. I am unable to do that because I am unfamiliar with POSTMAN to some extent.
Below is the python code that I have.
import requests
import ast
import json
resp1 = {}
url = 'http://myflaskapiurl:port/route'
files = {'file': open(r'file that should be uploaded to the server', 'rb')}
r = requests.post(url, files=files, data={"flag":2})
headers = {
'content-type': "multipart/form-data",
'Content-Type': "application/x-www-form-urlencoded",
'cache-control': "no-cache",
}
resp1 = ast.literal_eval(r.text)
print(resp1)
I am struggling with the question whether the data and file that I am trying to post to the server should be in raw json or form-data or x-www-form-urlencoded section of body. Also what should be the actual structure.
Because every time I POST this data using form-data or x-www-form-urlencoded section of body I get the error saying
werkzeug.exceptions.BadRequestKeyError
werkzeug.exceptions.HTTPException.wrap..newcls: 400 Bad Request: KeyError: 'file'
This is how it should look like:
The "params" tab should be empty, maybe you're adding a second file parameter there?
I have a client id and client secret and am attempting to generate an auth token by following Sitescout's api docs. I'm using python module Requests and am getting a 400 status code back, aka malformed request, but I can't seem to figure out why.
My code:
import requests
url = "https://api.sitescout.com/oauth/token"
headers = {
"Host": "api.sitescout.com",
"Authorization": "Basic YmVldGhvdmVuOmxldG1laW4=",
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/json",
"Content-Length": "41"
}
# Do the HTTP request
response = requests.post(url, headers=headers)
response.status_code
That is the fake base64 Authorization header provided in the docs so this snippet returns a 401 error, aka unauthorized (I have my own auth of course).
Can anyone tell me what's wrong with this?
It has been resolved. I did not put grant_type=client_credentials which, when added, returns a 200.
The docs say "Optionally, you can add form parameter scope to indicate which scopes you are requesting access to; the scope values must be space delimited (e.g., STATS AUDIENCES)." But it is the "&scope=STATS" param that is optional, not all params. The example confused me.
Now my code reads
...
params = { "grant_type" : "client_credentials" }
response = requests.post(url, headers=headers, params=params)
...
which works.