Issues with JSON Data in Python - python

I am working on a project to incorporate Verizon Thingspace REST APIs into a Python program.
A co-worker provided me with an example in CURL that works (I am not familiar with Curl so am trying to convert into Python).
curl -X POST --header "Content-Type: application/json" --header "Accept: application/json" --header "VZ-M2M-Token: 621d9779-f8bc-4fe9-91dd-b726c52e7117" --header "Authorization: Bearer 89ba225e1438e95bd05c3cc288d3591" -d "{\"accountName\": \"TestAccount-1\"}" https://thingspace.verizon.com/api/m2m/v1/devices/actions/list
I'm trying to convert this exact same request into a Python function. Here's what I have:
import requests
def getList(token):
url = "https://thingspace.verizon.com/api/m2m/v1/devices/actions/list"
headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer 89ba225e1438e95bd05c3cc288d3591",
"VZ-M2M-Token": "f7ef3a35-abb6-418b-92d4-7cdac8b06c5f",
}
data = {"accountName": "TestAccount-1"}
print data
deviceList = requests.post(url, data=data, headers=headers)
print headers
print (deviceList.status_code, deviceList.reason, deviceList.text)
return deviceList
When I run this, I get the following error message back in JSON:
(400, 'Bad Request',
u'{"errorCode":"REQUEST_FAILED.UnexpectedError","errorMessage":"Could
not read document: Unrecognized token \'accountName\': was expecting
(\'true\', \'false\' or \'null\')\n at [Source:
java.io.PushbackInputStream#51ceaf1d; line: 1, column: 13]; nested
exception is com.fasterxml.jackson.core.JsonParseException:
Unrecognized token \'accountName\': was expecting (\'true\', \'false\'
or \'null\')\n at [Source: java.io.PushbackInputStream#51ceaf1d;
line: 1, column: 13]"}')
You can reference the API information here: https://thingspace.verizon.com/developer/apis#/Connectivity%20Management/API%20Reference/Retrieve%20Device%20Information.html
I believe there might be something wrong with my JSON string but I need another set of eyes.

data is not automatically converted to json, you have to do this explicitly:
deviceList = requests.post(url, data=json.dumps(data), headers=headers)

Related

curl POST works in command line but not with Python

I need to run a curl POST to obtain API token as following:
curl - i -v -k -X POST -d '{"authType":"LOCAL","password":"mypw","username":"admin"}' --header "Content-Type:application/json" "https://x.x.x.x:xxxx/myapi_auth_path/login"
Everything runs well and I can obtain the token.
Now I want to do that with Python requests:
import requests
address = "https://x.x.x.x:xxxx/myapi_auth_path/login"
headers = {"Content-Type": "application/json"}
data = {"authType": "LOCAL",
"password": "mypw",
"username": "admin"}
res = requests.post(address, data=data, headers=headers, verify=False)
I get this error:
Expecting value: line 1 column 1 (char 0)
What is wrong with the Python code?
You're using data=data which means your data dict will be form-encoded.
You can use json=data instead (this will also set the Content-Type header for you)
It's covered in this section of the docs,

How to pass a list to data parameter in requests.patch?

I'm trying to add a role to a user in Auth0 via requests in python, but I'm having problems with the data part. I've tried to send this data passing a pure list, using json parameter instead of data and other options...
requests.patch(
url='my_url',
data=json.dumps(["my_role_id"]),
headers={'Authorization': 'Bearer my_token',
'Content-Type': 'application/json'}
)
Following the docs, if I try to send the same data via cURL or in a client like Insomnia, it works.
curl --request PATCH \
--url 'https://{extension_url}/users/{user_id}/roles' \
--header 'Authorization: Bearer {access_token}' \
--header 'Content-Type: application/json' \
--data '[ "{role_id}" ]'
The data content passed to service in the python sample is not the same as in the cURL sample. Try this (postman-echo helps to figure out what is going on):
import requests
import json
role_ids = ["my-role-id"]
role_id_array = [ "{%s}" % x for x in role_ids ]
resp = requests.patch(
url='http://postman-echo.com/patch',
data=json.dumps(role_id_array),
headers={'Authorization': 'Bearer my_token',
'Content-Type': 'application/json'}
)
print(resp.content)
I solved it! My url was wrong with the user_id incomplete and Auth0's authorization API didn't tell me that.

change curl cmd to python

I am a beginner. I am trying to change a curl cmd to an actually Post request in my python code.
Each time, I am getting either a 404 or 400 errors. I am a bit lost. Thanks.
Curl request : (echo -n '{"data": "'; base64 test-1.pdf; echo '", "extension": ".pdf"}') | curl -X POST -H "Content-Type: application/json" -d #- http://localhost:5000
My python code:
import json
import requests
url ='http://localhost:5000/POST'
newHeaders = {'Content-Type': 'application/json'}
response = requests.post(url, json={"data": "'; base64 test-1.pdf; echo '", "extension": ".pdf"},headers=newHeaders)
print("Status code: ", response.status_code)
response_Json = response.json()
print("Printing Post JSON data")
print(response_Json['data'])
print("Content-Type is ", response_Json['headers']['Content-Type'])
Your URL is wrong and should not have the /POST at the end, but in addition to that, you need to actually base64-encode the test-1.pdf (this is what the shell command that runs curl is doing).
You could use this (combined with the code in the question) to put the correct value into the parameters dictionary.
import base64
#...
b64 = base64.b64encode(open("test-1.pdf", "rb").read()).decode()
response = requests.post(url,
json={"data": b64,
"extension": ".pdf"},
headers=newHeaders)

mapping a curl command to equal python requests function

Really would appreciate some help to understand what I'm missing.
I have a working curl command that I need to map to an equal python function using requests.
All my attempts end up failing with a message of :
requests.exceptions.ConnectionError: ('Connection aborted.', error(32, 'Broken pipe'))
The original curl command is:
curl -X POST "https://x.x.x.x/api/upload" -H "accept: application/json"
-H "authorization: Basic BlaBla" -H "Content-Type: multipart/form-data"
-F "file=#SomeFile.zip;type=application/zip"
My failing python code is:
def importZip(self, fAuth, infile, dir=''):
trgtURL = fAuth.url+"/api/upload"
headers = {'Content-Type': 'multipart/form-data'}
data = {'upload':''}
files = {'file': (infile, open(dir+infile,'rb'))}
r = fAuth.session.post(trgtURL, files=files, data=data)
fAuth is just a class I use to authenticate and retain the session for follow up calls. I can use the fAuth instance to do gets no problem, so I suspect the problem isn't tied to the underlying session.
Any ideas or insight are greatly appreciated.
-H "accept: application/json" -H "Content-Type: multipart/form-data" equal to {"Accept": "application/json"} in python. Content-Type is not necessary, because library will add it.
-H "authorization: Basic BlaBla" is a bit special in header. So you should read Authentication
So you job is to add auth param, and modify your headers by your command example.
def importZip(self, fAuth, infile, dir=''):
trgtURL = fAuth.url+"/api/upload"
headers = {"Accept": "application/json"}
files = {'file': (infile, open(dir+infile,'rb'), "application/zip")}
auth = (user,passwd)
r = fAuth.session.post(trgtURL, headers=headers, files=files, auth=auth)

Can't post file using python requests - Translation from curl

The following command works, but I can't reproduce it using python-requests (2.18.4) :
curl -X POST -H "Authorization: Bearer ..." \
-H "Content-Type: multipart/form-data" \
-F 'metadata={...}
-F 'data=#data.bz2;type=application/octet-stream'
https://www....com
Using the send_devices below, I receive "Unsupported Media Type""
def send_devices(basic_auth):
endpoint_api = ' https://www....com'
with open('data.bz2','rb') as payload:
response = requests.post(endpoint_api, data={'metadata': ...,
'data': payload},
headers={'Authorization': 'Bearer {0}'.format(basic_auth})
After some comments, I also tried and the error now is "Invalid Metadata Json String":
def send_devices(basic_auth):
endpoint_api = ' https://www....com'
files = {'file': ('data.bz2', open('data.bz2', 'rb'), 'application/octet-stream')}
response = requests.post(endpoint_api, data={"metadata": {"extensions":{"urnType":"IDFA"}}},
files=files, headers={'Authorization': 'Bearer {0}'.format(basic_auth)})
In the first example, was missing the file type
'data': ('data.bz2', open('data.bz2', 'rb'), 'application/octet-stream'),
In the second example, is necessary to add extra post data on the same files dict. Even if is not a dict:
'metadata': ('metadata.csv', json.dumps({"extensions": ...}))}
The solution:
def send_devices(basic_auth):
endpoint_api = ' https://www....com'
files = {'data': ('data.bz2', open('data.bz2', 'rb'), 'application/octet-stream'),
'metadata': ('metadata.csv', json.dumps({"extensions": ...}))}
response = requests.post(endpoint_api, files=files,
headers={'Authorization': 'Bearer {0}'.format(basic_auth)})
Make sure the payload is formatted correctly. It appears you are missing an '{' in your second object within your payload.
The HTTP 415 Unsupported Media Type client error response code indicates that the server refuses to accept the request because the payload format is in an unsupported format.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/415
You should put it as file (not as data).
r = requests.post(url, files={'file': open('data.bz2', 'rb')})
works fine.

Categories