how to make post request in python - python

Here is the curl command:
curl -H "X-API-TOKEN: <API-TOKEN>" 'http://foo.com/foo/bar' --data #
let me explain what goes into data
POST /foo/bar
Input (request JSON body)
Name Type
title string
body string
So, based on this.. I figured:
curl -H "X-API-TOKEN: " 'http://foo.com/foo/bar' --data '{"title":"foobar","body": "This body has both "double" and 'single' quotes"}'
Unfortunately, I am not able to figure that out as well (like curl from cli)
Though I would like to use python to send this request.
How do i do this?

With the standard Python httplib and urllib libraries you can do
import httplib, urllib
headers = {'X-API-TOKEN': 'your_token_here'}
payload = "'title'='value1'&'name'='value2'"
conn = httplib.HTTPConnection("heise.de")
conn.request("POST", "", payload, headers)
response = conn.getresponse()
print response
or if you want to use the nice HTTP library called "Requests".
import requests
headers = {'X-API-TOKEN': 'your_token_here'}
payload = {'title': 'value1', 'name': 'value2'}
r = requests.post("http://foo.com/foo/bar", data=payload, headers=headers)

Related

Post requests in python vs curl

Can someone please suggest the correct syntax for calling the below using python?
curl "https://sometest.api.token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id={client_id}&client_secret={client_secret}"
My attempt:
import requests
import json
credentials='1111'
secret='2222'
url = 'https://sometest.api.token'
body = {'client_credentials':credentials,'client_secret':secret}
headers = {'Content-type': 'application/x-www-form-urlencoded'}
r = requests.post(url, data=json.dumps(body), headers=headers)
Due to documentation, if you want to send some form-encoded data, you simply pass a dictionary to the data argument.
So you have to try:
import requests
import json
credentials='1111'
secret='2222'
url = 'https://sometest.api.token'
body = {'client_credentials':credentials, 'client_secret':secret}
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
r = requests.post(url, data=body, headers=headers)
And also your parameters in python code are different from parameters in curl, maybe you have to check it.

Trouble converting curl commands to python requests

I'm trying to grab some data from a website using API, but I'm having trouble converting the example curl command to python requests.
example curl command
curl -X POST "some_url" \
-H "accept: application/json" \
-H "Authorization: <accesstoken>" \
-d #- <<BODY
{}
BODY
My python requests that didn't work
headers = {
'Authorization': "Bearer {0}".format(access_token)
}
response = requests.request('GET', "some_url",
headers=headers, allow_redirects=False)
I get error code 400, can anyone help me figure out what was wrong?
The equivalent requests code for your curl should be:
import requests
headers = {
'accept': 'application/json',
'Authorization': '<accesstoken>',
}
data = "{} "
response = requests.post('http://some_url', headers=headers, data=data)
You can use https://curl.trillworks.com/ to convert your actual curl invocation (note that it won't handle heredocs, as in your example).
If you see different behavior between curl and your python code, dump the HTTP requests and compare:
Python requests - print entire http request (raw)?
How can I see the request headers made by curl when sending a request to the server?

Converting curl command to Python request

The curl command that I have that works properly is -
curl -X GET -H "Authorization: Basic <base64userpass>" -H "Content-Type: application/json" "http://<host>/bamboo/rest/api/latest/result/<plankey>.json?expand=results.result&os_authType=basic"
In Python, this is what I currently have -
headers = {'Authorization': 'Basic <base64userpass>', 'Content-Type': 'application/json'}
datapoints = {'expand': 'results.result', 'os_authType': 'basic'}
url = "http://<host>/bamboo/rest/api/latest/result/<plankey>.json"
r = requests.get(url, headers=headers, data=datapoints)
The response I get when using the Python request is <Response [403]>, but when using curl I get back the expected data.
What am I missing here?
Thanks.
You should use the auth option of requests to do basic authentication.
There are more headers that the CURL command-line handle for you (and requests will not handle them unless you use the auth):
>>> from requests.auth import HTTPBasicAuth
>>> requests.get('https://api.github.com/user', auth=HTTPBasicAuth('user', 'pass'))
Or just use:
>>> requests.get('https://api.github.com/user', auth=('user', 'pass'))
(Change the URL and everything).
Also note that requests should get the params= (and not data=).

Python requests doesn't upload file

I am trying to reproduce this curl command with Python requests:
curl -X POST -H 'Content-Type: application/gpx+xml' -H 'Accept: application/json' --data-binary #test.gpx "http://test.roadmatching.com/rest/mapmatch/?app_id=my_id&app_key=my_key" -o output.json
The request with curl works fine. Now I try it with Python:
import requests
file = {'test.gpx': open('test.gpx', 'rb')}
payload = {'app_id': 'my_id', 'app_key': 'my_key'}
headers = {'Content-Type':'application/gpx+xml', 'Accept':'application/json'}
r = requests.post("https://test.roadmatching.com/rest/mapmatch/", files=file, headers=headers, params=payload)
And I get the error:
<Response [400]>
{u'messages': [], u'error': u'Invalid GPX format'}
What am I doing wrong? Do I have to specify data-binary somewhere?
The API is documented here: https://mapmatching.3scale.net/mmswag
Curl uploads the file as the POST body itself, but you are asking requests to encode it to a multipart/form-data body. Don't use files here, pass in the file object as the data argument:
import requests
file = open('test.gpx', 'rb')
payload = {'app_id': 'my_id', 'app_key': 'my_key'}
headers = {'Content-Type':'application/gpx+xml', 'Accept':'application/json'}
r = requests.post(
"https://test.roadmatching.com/rest/mapmatch/",
data=file, headers=headers, params=payload)
If you use the file in a with statement it'll be closed for you after uploading:
payload = {'app_id': 'my_id', 'app_key': 'my_key'}
headers = {'Content-Type':'application/gpx+xml', 'Accept':'application/json'}
with open('test.gpx', 'rb') as file:
r = requests.post(
"https://test.roadmatching.com/rest/mapmatch/",
data=file, headers=headers, params=payload)
From the curl documentation for --data-binary:
(HTTP) This posts data exactly as specified with no extra processing whatsoever.
If you start the data with the letter #, the rest should be a filename. Data is posted in a similar manner as --data-ascii does, except that newlines and carriage returns are preserved and conversions are never done.

Python: Bad request in POST using requests

I am supposed to send this:
curl --header "Content-Type: text/plain" --request POST --data "ON" example.com/rest/items/z12
Instead, I am sending this:
import requests
headers = {"Content-Type": "text/plain"}
url = 'http://example.com/rest/items/z12'
_dict = {"ON": ""}
res = requests.post(url, auth=('demo', 'demo'), params=_dict, headers=headers)
And I am getting an Error 400 (Bad Request?)
What am I doing wrong?
The POST body is set to ON; use the data argument:
import requests
headers = {"Content-Type": "text/plain"}
url = 'http://example.com/rest/items/z12'
res = requests.post(url, auth=('demo', 'demo'), data="ON", headers=headers)
The params argument is used for URL query parameters, and by using a dictionary you asked requests to encode that to a form encoding; so ?ON= is added to the URL.
See the curl manpage:
(HTTP) Sends the specified data in a POST request to the HTTP server, in the same way that a browser does when a user has filled in an HTML form and presses the submit button.
and the requests API:
data – (optional) Dictionary, bytes, or file-like object to send in the body of the Request.
params parameter in the requests.post method is used to add GET parameters to the URL. So you are doing something like this :
curl --header "Content-Type: text/plain" --request POST example.com/rest/items/z12?ON=
You should instead use the data parameter.
import requests
headers = {"Content-Type": "text/plain"}
url = 'http://example.com/rest/items/z12'
res = requests.post(url, auth=('demo', 'demo'), data="ON", headers=headers)
Moreover, if you give a dictionnary to the data parameter, it will send the payload as "application/x-www-form-urlencoded". In your curl command, you send raw string as payload. That's why I changed a bit your example.

Categories