Python Requests, getting back: Unexpected character encountered while parsing value: L. Path - python

I am attempting to get an auth token from The Trade Desk's (sandbox) api but I get back a 400 response stating:
"Error reading Content-Type 'application/json' as JSON: Unexpected
character encountered while parsing value: L. Path '', line 0,
position 0."
Whole response.json():
{u'ErrorDetails': [{u'Reasons': [u"Error reading Content-Type 'application/json' as JSON: Unexpected character encountered while parsing value: L. Path '', line 0, position 0."], u'Property': u'TokenRequest'}], u'Message': u'The request failed validation. Please check your request and try again.'}
My script (runnable):
import requests
def get_token():
print "Getting token"
url = "https://apisb.thetradedesk.com/v3/authentication"
headers = {'content-type': 'application/json'}
data = {
"Login":"logintest",
"Password":"password",
"TokenExpirationInMinutes":60
}
response = requests.post(url, headers=headers, data=data)
print response.status_code
print response.json()
return
get_token()
Sandbox docs here
I believe this means my headers var is not being serialized correctly by requests, which seems impossible, or not being deserialized correctly by The Trade Desk. I've gotten into the requests lib but I can't seem to crack it and am looking for other input.

You need to do
import json
and convert your dict into json:
response = requests.post(url, headers=headers, data=json.dumps(data))
Another way would be to explicitely use json as parameter:
response = requests.post(url, headers=headers, json=data)
Background: In the prepare_body method of requests a dictionary is explicitely converted to json and a content-header is also automatically set:
if not data and json is not None:
content_type = 'application/json'
body = complexjson.dumps(json)
If you pass data=data then your data will be only form-encoded (see http://docs.python-requests.org/en/latest/user/quickstart/#more-complicated-post-requests). You will need to explicitely convert it to json, if you want json to be the content-type of your http body.
Your follow-up question was about why headers don't have to be converted to json. Headers can be simply passed as dictionary into the request. There's no need to convert it to json. The reason is implementation specific.

Related

Python http.client giving empty string when I use response.read().decode()

I am using http.client to hit a POST api and get the json response. My code is working correctly when I print response.read(). However, for some reason, this response is limited to only 20 results and the total count of results is over 20,000. I want to get the complete response in a variable using response.read().decode(), I am hoping that the variable will contain the complete json string. The issue is that I am getting an empty string when I used decode(). How do I get this done? How do I get the complete results?
import http.client
host = 'jooble.org'
key = 'API_KEY'
connection = http.client.HTTPConnection(host)
#request headers
headers = {
"Content-type": "application/json"}
#json query
body = '{ "keywords": "sales", "location": "MA"}'
connection.request('POST','/api/' + key, body, headers)
response = connection.getresponse()
print(response.status, response.reason)
print(response.read())
print(response.read().decode())
Don't call response.read() twice. response is a stream, so each call to read() continues from where the previous one ended. Since the first call is reading the entire response, the second one doesn't read anything.
If you want to print the encoded and decoded response, assign response.read() to a variable, then decode that.
data = response.read()
print(data)
print(data.decode())
But this can be done more simply using the requests module.
import requests
host = 'jooble.org'
key = 'API_KEY'
body = { "keywords": "sales", "location": "MA"}
response = requests.post(f'https://{host}/api/{key}', json=body)
print(response.content)
Note that in this version body is a dictionary, not a string. The json parameter automatically converts it to JSON.

Using JSON data from API GET to POST to another API via python script

So, I'm new to python and am struggling, self taught, and still learning to code. So be easy on me :)
I am using a script to get data from one source (Jira's API) and trying to use those results to post to another (PowerBi).
I've managed to successfully get the data, I just don't know how to pass the data to this other API.
I know how to use the GET and POST calls, it's just using the data from one to another than I can't seem to find anything about. Assuming since what I'm asking for is very specific?
edit: I also want to mention that while my get is asking for specific data, I'm getting more than I actually need. So I need a way to specify (hopefully) what data is actually being sent to PowerBi's API
import json
import requests
url = 'https://mydomain.atlassian.net/rest/api/2/search'
headers = { 'Content-Type' : 'application/json',
'Authorization' : 'Basic 123456789' }
params = {
'jql' : 'project IN (, PY, CH, NW, RP, DP, KR, DA, RE, SS, CR, CD, AB) AND issueType=incident AND statusCategory!=Done',
'startAt': 0,
'maxResults' : 50,
}
requestget = requests.get(url, headers=headers, params=params)
if requestget.status_code == 200:
print(json.dumps(json.loads(requestget.text), sort_keys=True, indent=4, separators=(",", ": ")))
else:
print("None")
Apologies if I miss understood what you were asking help on, but you could use this to send a POST request as json.
request = urllib.request.Request()#Put the powerbi api here
request.add_header('Content-Type', 'application/json; charset=utf-8')
jsondata = #your json data
jsonBytes = jsondata.encode('utf-8')
#Has to be bytes
request.add_header('Content-Length', len(jsonBytes))
response = urllib.request.urlopen(request, jsonBytes)
You could go with a requests.post instead.
jsondata = #put json data here
headers = {'content-type': 'application/json'}
response = requests.post(url, data=json.dumps(jsondata), headers=headers)
Requests documentation

Error "400 Bad request" when sending JSON object to an api using Python

Here is a snippet of code:
api_url = {url}
auth_head = {key: value} << my api authentication header
data = {'title':'Python'} << the valid json object format that the api accepts
Here is what I tried:
data = json.dumps(data)
json_obj = json.loads(data)
response = requests.post(api_url, headers = auth_head, data = json_obj)
print(response.text)
Here is the output:
"400 Bad request"
To make sure the url and my api token key work I tried GET:
response = requests.get(api_url, headers = auth_head)
print(response.status_code)
Output:
"200"
So the url and api token work fine. I feel I am not sending the correct json object construct that the api wants
You don't need to send data as json. Just send data as dictionary. It will accept. requests automatically will encode your dictionary to json

How do I make a GET request with JSON in the request body

I need to send this JSON array in a GET request
{"user": "jähn", "id": 3}
I tried to use
data = '{"user": "jähn", "id": 3}'
headers = {
'Content-type': 'application/json',
'Accept': 'text/plain'
}
request = urllib.request.Request(self.update_url, data=data,
headers=headers, method='GET')
response = urllib.request.urlopen(request)
But its failing with: TypeError: POST data should be bytes or an iterable of bytes. It cannot be of type str.
Another thing that I find quite weird is that it tells me about POST data although I set the method on the Request to GET.
Since this is a simple script I'd prefer not to use a library like python-requests
You cannot make a GET request with a JSON-encoded body, as a GET request only ever consists of the URL and the headers. Parameters are encoded into the URL using URL encoding instead, there is no option to encode such parameters to JSON instead.
You create URL-encoded parameters with the urllib.parse.urlencode() function, then appended to the URL with ?.
from request.parse import urlencode
data = {"user": "jähn", "id": 3} # note, a Python dictionary, not a JSON string
parameters = urlencode(data)
response = urllib.request.urlopen('?'.join((self.update_url, parameters)))
Do not use the data parameter; using that keyword argument forces a request to use the POST method:
data must be a bytes object specifying additional data to send to the server, or None if no such data is needed. Currently HTTP requests are the only ones that use data; the HTTP request will be a POST instead of a GET when the data parameter is provided. data should be a buffer in the standard application/x-www-form-urlencoded format.

Django calls with Json. Common_Unsupported_Media_Type

I'm trying to make a RESTful api call in python/django with requests.post
I can get requests.get(url=url, auth=auth) to work. Similar call in the same api family for this company
I'm trying to do:
data = {'start': 13388, 'end': 133885, 'name': 'marcus0.5'}
r = requests.post(url=url, auth=auth, headers={'Accept': 'application/json'}, data=data)
and I get the following error:
>>> r.text
u'{"status":"error","errorCode":"COMMON_UNSUPPORTED_MEDIA_TYPE","incidentId":"czEtbXNyZXBvcnRzMDQuc3RhZ2V4dHJhbmV0LmFrYW1haS5jb20jMTM3NTgxMzc3MTk4NQ==","errorMessage":"The server is refusing to service the request because the entity of the request is in a format not supported by the requested resource for the requested method.. Content type \'application/x-www-form-urlencoded;charset=UTF-8\' not supported."}'
I think it has something to do with the json, but I'm not sure what and I'm not sure how to fix it. Any ideas?
Extra info [not sure if it applies]:
I imported
import requests, django
I know the the auth is correct and I tested it with the get method
You want to set the Content-Type parameter of your request to 'application/json', not the Accept parameter.
Taken from w3.org:
The Accept request-header field can be used to specify certain media types which are acceptable for the response.
Try this instead:
import json
data = {'start': 13388, 'end': 133885, 'name': 'marcus0.5'}
r = requests.post(url=url, auth=auth, data=json.dumps(data),
headers={'content-type': 'application/json'})
EDIT:
There is a little bit of confusion (for me as well) about when to send data as a dict or a json encoded string (ie. the result of json.dumps). There is an excellent post here that explains the problem. For a brief summary send a dict when the API requires form-encoded data, and a json encoded string when it requires json-encoded data.

Categories