Python Post call throwing 400 Bad Request - python

I am writing a python script which will call a REST POST endpoint but in response I am getting 400 Bad Request where as if I do same request with curl, it returns me 200 OK. Code snippet for python script is below
import httplib,urllib
def printText(txt):
lines = txt.split('\n')
for line in lines:
print line.strip()
httpServ = httplib.HTTPConnection("127.0.0.1", 9100)
httpServ.connect()
params = urllib.urlencode({"externalId": "801411","name": "RD Core","description": "Tenant create","subscriptionType": "MINIMAL","features": {"capture":False,"correspondence": True,"vault": False}})
headers = {"Content-type": "application/json"}
httpServ.request("POST", "/tenants", params, headers)
response = httpServ.getresponse()
print response.status, response.reason
httpServ.close()
and corresponding curl request is
curl -iX POST \
-H 'Content-Type: application/json' \
-d '
{
"externalId": "801411",
"name": "RD Core seed data test",
"description": "Tenant for Core team seed data testing",
"subscriptionType": "MINIMAL",
"features": {
"capture": false,
"correspondence": true,
"vault": false
}
}' http://localhost:9100/tenants/
Now I am not able figure out where is the issue in python script.

Try using requests (install with pip install requests) instead of urllib.
Also, enclose your data as JSON in the request body, don't pass them as URL parameters. You are passing JSON data in your curl example as well.
import requests
data = {
"externalId": "801411",
"name": "RD Core",
"description": "Tenant create",
"subscriptionType": "MINIMAL",
"features": {
"capture": False,
"correspondence": True,
"vault": False
}
}
response = requests.post(
url="http://localhost:9100/tenants/",
json=data
)
print response.status_code, response.reason
EDIT
From https://2.python-requests.org/en/master/user/quickstart/#more-complicated-post-requests:
Note, the json parameter is ignored if either data or files is passed.
Using the json parameter in the request will change the Content-Type
in the header to application/json.

The problem in your code is, you set Content-Type header as application/json and not sending data in json format
import httplib, json
httpServ = httplib.HTTPConnection("127.0.0.1", 9100)
httpServ.connect()
headers = {"Content-type": "application/json"}
data = json.dumps({
"externalId": "801411",
"name": "RD Core",
"description": "Tenant create",
"subscriptionType": "MINIMAL",
"features": {
"capture": False,
"correspondence": True,
"vault": False
}
})
# here raw data is in json format
httpServ.request("POST", "/tenants", data, headers)
response = httpServ.getresponse()
print response.status, response.reason
httpServ.close()

Related

JSON parse error when using python requests for an API

If I run a curl statement in bash I get the result I want with no problem.
curl --header 'Content-Type: application/json' --header 'Authorization: Token ABC123' --data '{"jsonrpc":"2.0","method":"enterprise/getEnterpriseEdges","params":{"with":["certificates","configuration","links","recentLinks","site","licenses","analyticsMode","selfHealing"],"edgeIds":[4723]},"id":34123423}' --request POST 'https://my-portal.velocloud.net/portal/'
When putting it into a python script, I keep getting this result instead of the massive JSON array of data.
{'jsonrpc': '2.0', 'error': {'code': -32603, 'message': 'JSON parse error'}, 'id': 1}
This is a copy of my Python script
import requests
payload_headers = {
"Content-Type": "application/json",
"Authorization": "Token ABC123"
}
payload_data = {
"jsonrpc": "2.0",
"method": "enterprise/getEnterpriseEdges",
"params": {
"with": ["certificates", "configuration", "links", "recentLinks", "site", "licenses", "analyticsMode", "selfHealing"],
"edgeIds": [4723]
},
"id": 34
}
response = requests.post("https://my-portal.velocloud.net/portal/", headers=payload_headers, data=payload_data, verify= False)
json_info = response.json()
print(json_info)
I was hoping to get a JSON output of the data like I get with the curl in bash, and eventually incorporate a loop to run through a list to get multiple JSONs to build out an API.
You need to dump the dict to str:
import json
response = requests.post("https://my-portal.velocloud.net/portal/",
headers=payload_headers,
data=json.dumps(payload_data),
verify=False)
Or just use json parameter:
response = requests.post("https://my-portal.velocloud.net/portal/",
headers=payload_headers,
json=payload_data,
verify=False)

Error 500 when requesting Datadog logs by Python Requests

I have the following curl command which works fine:
curl -X POST -H 'content-type: application/json' -H "DD-API-KEY: ${api_key}" -H "DD-APPLICATION-KEY: ${app_key}" \
-d '{
"query": "service:my_service",
"time": {
"from": "2019-11-28T00:00:00Z",
"to": "2019-11-28T16:00:00Z"
},
"sort": "asc",
"limit": 1000
}' "https://api.datadoghq.com/api/v1/logs-queries/list" -o output3.json5
Then I convert this requests to Python Requests, and the curl method works but Python returns a 500 error without any details.
import requests
def main():
headers = {
'content-type': 'application/json',
'DD-API-KEY': 'AAA',
'DD-APPLICATION-KEY': 'XXX',
}
data = {
"query": "service:my_service",
"time": {
"from": "now - 1h",
"to": "now"
},
"sort": "asc",
"limit": 50
}
response=requests.post("https://api.datadoghq.com/api/v1/logs-queries/list",headers=headers, data=data)
I tried it outside my Docker guessing that maybe connection was the key, but it doesn't work either.
Point both of those at a service like httpbin to see how they differ.
Requests' data option for POST requests generates form-encoded data by default, while curl passes the JSON string through directly. You can manually encode your payload as a JSON string:
import json
response = requests.post(..., data=json.dumps(data))
# ^^^^^^^^^^
or if you have Requests version 2.4.2 or later you can use the json parameter to have your dict converted to JSON automatically:
response = requests.post(..., json=data)
# ^^^^

python requests: PUT request to azure fails with 415 error

So I'm trying to use python requests to make a PUT request to Azure (to create/update notification hub - https://learn.microsoft.com/en-us/rest/api/notificationhubs/notificationhubs/createorupdate#mpnscredential .
My code:
url = "https://management.azure.com/subscriptions/mysub/resourceGroups/Default-NotificationHubs-WestEurope/providers/Microsoft.NotificationHubs/namespaces/myNamespace/notificationHubs/notificationHubName?api-version=2016-03-01"
bearer_token = "my very long token"
headers = {
"dataType": "json",
"accept":"application/json",
"contentType":"application/json",
"Authorization": "Bearer " + bearer_token }
filepath = "/Users/..../pathTo.p12"
with open(filepath) as fh:
byte_array_p12 = fh.read()
data = {
'location': "West Europe",
'properties.apnsCredential': {
'properties.apnsCertificate': byte_array_p12,
'properties.certificateKey': "some nice pass"
}
}
r = requests.put(url, data, headers = headers)
But running r gives me 415 error.
r.text
u'{"error":{"code":"UnsupportedMediaType","message":"The content media type \'application/x-www-form-urlencoded\' is not supported. Only \'application/json\' is supported."}}'
Where did that \'application/x-www-form-urlencoded\' come from? I am explicitly setting headers for that request, and that one is not included... I am clueless.
I have tried the "Try" functionality on the afformentioned Azure page, where you can try constructing the body yourself, but it is buggy...
Thanks for any help!
The HTTP header should Content-Type and not contentType.
headers = {
"dataType": "json",
"accept":"application/json",
"Content-Type":"application/json",
"Authorization": "Bearer " + bearer_token }
Also, parameter data should be JSON encoded.
r = requests.put(url, json=data, headers=headers)

How to POST this API code in Python 3 with Requests module? Keep getting 405 error

I want to use the API for a link shortener site. I know the example given is in curl and that -H means there's a header as well as PUT means it's posting, but I can't seem to get the result I want no matter how much I try. All I can do is either get a 405 error or break it.
I am on Windows with Python 3 and do have requests installed already.
For developers Shorte.st prepared API which returns responses in JSON format.
Currently there is one method which can be used to shorten links on behalf of your account.
Take a look on the sample below to learn how to use our API.
curl -H "public-api-token: (my token)" -X PUT -d
"urlToShorten=google.com" https://api.shorte.st/v1/data/url
When received,
{"status":"ok","shortenedUrl":"http:\/\/sh.st\/XXXX"}
I have tried a few things namely,
import requests
import json
gogo = { 'public-api-token: (my token)' : 'urlToShorten=google.com'}
yep = requests.post('https://api.shorte.st/v1/data/url',
data=json.dumps(gogo))
print (yep.text)
shows me an HTML webpage with error 405.
import requests
import json
gogo = { 'public-api-token' : '(my token)', 'urlToShorten=' : 'google.com'}
yep = requests.post('https://api.shorte.st/v1/data/url',
data=json.dumps(gogo))
print (yep.text)
Also shows me a webpage with error 405.
I now know the -H is for headers and am using this while still just gets me the page.
import requests
import json
headers = { 'public-api-token' : '(my token)' }
gogo = {"urlToShorten" : "google.com"}
yep = requests.post('https://api.shorte.st/v1/data/url',
data=json.dumps(gogo), headers=headers)
print (yep.text)
and another attempt another 405
gogo = {"public-api-token: (my token)" : "urlToShorten=google.com"}
yep = requests.post('https://api.shorte.st/v1/data/url',
data=json.dumps(gogo))
print (yep.text)
Even this just gives me a full html page/405 if I take off the text.
headers = { "public-api-token: (my token)" : "urlToShorten=google.com" }
yep = requests.post('https://api.shorte.st/v1/data/url', headers=headers)
print (yep.text)
You are putting your PUT payload in the headers. Put it in the body instead. Your payload is not JSON, so there is no need to try and treat it as such.
The headers need to be specified as a dictionary with the header name and token as key and value. The parameters for the payload can be treated in the same way.
You are also using the wrong requests method; to send a PUT request, use the put function instead:
headers = {'public-api-token': '(my token)'}
payload = {'urlToShorten': 'google.com'}
response = requests.put(
'https://api.shorte.st/v1/data/url',
data=payload, headers=headers)
print(response.json())
The response object has a json() method to decode the JSON data returned by the API; it'll give you the Python data structure corresponding to the JSON text.
I don't have a token for the service you are using; I created a demo using the httpbin.org service; it reflects what was sent as a JSON response:
>>> import requests
>>> headers = {'public-api-token': '(my token)'}
>>> payload = {'urlToShorten': 'google.com'}
>>> response = requests.put(
... 'http://httpbin.org/put',
... data=payload, headers=headers)
>>> from pprint import pprint
>>> pprint(response.json())
{u'args': {},
u'data': u'',
u'files': {},
u'form': {u'urlToShorten': u'google.com'},
u'headers': {u'Accept': u'*/*',
u'Accept-Encoding': u'gzip, deflate',
u'Content-Length': u'23',
u'Content-Type': u'application/x-www-form-urlencoded',
u'Host': u'httpbin.org',
u'Public-Api-Token': u'(my token)',
u'User-Agent': u'python-requests/2.5.0 CPython/2.7.9 Darwin/14.1.0'},
u'json': None,
u'origin': u'94.118.96.0',
u'url': u'http://httpbin.org/put'}
If you compare that to the output produced for curl sending a PUT request to the same URL you'll see the same results are produced:
$ curl -H "public-api-token: (my token)" -X PUT \
-d "urlToShorten=google.com" http://httpbin.org/put
{
"args": {},
"data": "",
"files": {},
"form": {
"urlToShorten": "google.com"
},
"headers": {
"Accept": "*/*",
"Content-Length": "23",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"Public-Api-Token": "(my token)",
"User-Agent": "curl/7.37.1"
},
"json": null,
"origin": "94.118.96.0",
"url": "http://httpbin.org/put"
}

QPX Express API from Python

I am trying to use Google's QPX Express API from python. I keep running into a pair of issues in sending the request. At first what I tried is this:
url = "https://www.googleapis.com/qpxExpress/v1/trips/search?key=MY_KEY_HERE"
values = {"request": {"passengers": {"kind": "qpxexpress#passengerCounts", "adultCount": 1}, "slice": [{"kind": "qpxexpress#sliceInput", "origin": "RDU", "destination": location, "date": dateGo}]}}
data = json.dumps(values)
req = urllib2.Request(url, data, {'Content-Type': 'application/json'})
f = urllib2.urlopen(req)
response = f.read()
f.close()
print(response)
based upon the code from: urllib2 and json
When I run the above code I get the following error message:
TypeError: POST data should be bytes or an iterable of bytes. It cannot be of type str.
I searched for a solution and adapted my code based upon the following question: TypeError: POST data should be bytes or an iterable of bytes. It cannot be str
I changed my code to this:
url = "https://www.googleapis.com/qpxExpress/v1/trips/search?key=AIzaSyCMp2ZnKI3J91sog7a7m7-Hzcn402FyUZo"
values = {"request": {"passengers": {"kind": "qpxexpress#passengerCounts", "adultCount": 1}, "slice": [{"kind": "qpxexpress#sliceInput", "origin": "RDU", "destination": location, "date": dateGo}]}}
data = json.dumps(values)
data = data.encode("utf-8")
req = urllib2.Request(url, data, {'Content-Type': 'application/json'})
f = urllib2.urlopen(req)
response = f.read()
f.close()
print(response)
However, when I run this code I get the following error message:
urllib.error.HTTPError: HTTP Error 400: Bad Request
I also tried changing utf-8 to ascii but I was unsuccessful. How can I get this working properly?
Here is a solution using the excelent requests library.
import json
import requests
api_key = "YOUR API KEY HERE"
url = "https://www.googleapis.com/qpxExpress/v1/trips/search?key=" + api_key
headers = {'content-type': 'application/json'}
params = {
"request": {
"slice": [
{
"origin": "TXL",
"destination": "LIM",
"date": "2015-01-19"
}
],
"passengers": {
"adultCount": 1
},
"solutions": 2,
"refundable": False
}
}
response = requests.post(url, data=json.dumps(params), headers=headers)
data = response.json()
print data
I am not sure why you request is not working. Maybe it is really the request parameters that were wrong. The date definitely needs to be in the future!
False needs to be in lowercase in JSON, so you need to quote it in Python, like this "refundable" : "false". Otherwise, your query looks good (obviously you'll need to update the date). By the way, it isn't good practice to include your API key in a public forum.

Categories

Resources