I'm trying to re-create the example available on this page
Of course I'm changing the client_id, secret, credit card etc... with my valid data (I haven't copy-pasted the example as is).
You can see my complete code here (I've hidden sensible data with *** ).
I can get the token without any problem, but when I post the payment request I get this back:
In [11]: r2.text
Out[11]: u'{"name":"MALFORMED_REQUEST","message":"The request JSON is not well formed.","information_link":"https://developer.paypal.com/webapps/developer/docs/api/#MALFORMED_REQUEST","debug_id":"*************"}'
I really can't understand why it says that my json is malformed :(
Anyone can help me? Thanks!
This is your code:
post_data = json.loads(s)
r2 = requests.post('https://api.sandbox.paypal.com/v1/payments/payment', headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token},
data = post_data)
You have a JSON string s that you convert to a Python object and post that to the server. As the docs say, if you pass a dict as your data, it gets form-encoded, not JSON-encoded. If you want data in any other format, you're supposed to encode it yourself, as in the example:
>>> r = requests.post(url, data=json.dumps(payload))
Since you already have the JSON-encoded string s, you can just send that.
You totally misunderstood what you should pass to requests.post() method. http://docs.python-requests.org/en/latest/user/quickstart.html#more-complicated-post-requests
You are trying to pass Python objects instead of JSON. #Janne's answer is an option, but it is more convenient to build data as Python object and then use json.dumps(obj) and pass result to requests.post().
Related
I'm trying to use the salesforce bulk api 2.0 to upsert some data, and they only accept csv data. In this documentation, for step 2, they say create the csv file. Then in step 4, I need to upload the csv data. I have code that doesn't throw any errors, but the record is not processed, which makes me think I am doing something wrong.
So I have the following as my csv_string:
csv_string = "Id, Name__c\n,\"Doe, John\""
Here is how I am currently sending the data
headers = {'Content-Type': 'text/csv', 'Accept': 'application/json'}
data = {'file': csv_string}
async with self.session.put(upload_url, data = data, headers = headers) as response:
r = await response.text()
print(r)
According to the documentation, I am supposed to get " response that includes the job ID, with a job state of Open." but =it just prints an empty line.
Then when I do step 16: Check the job status and results, it successfully returns JobComplete and response.text() returns the following: "sf__Id","sf__Created",file=Id%2C+Name__c%0A%2C+%22Doe%2C+John%22 which is basically a url encoded version of my csv_string. There is no change to the data in salesforce, so the upsert fails. The fact that an empty line is printed out makes me believe that I am not passing the csv in correctly.
I've tried using aiohttp's FormData, but that changes the data type to multi-part encoded which is not accepted. I've also tried passing data = csv_string which makes salesforce return an error. I was thinking maybe I need to pass it in as binary data, for example, when you open a file using open("file_name", "rb"), but I don't know how to convert this existing string to binary data. Can someone give an example of how to pass csv data in a request using aiohttp? Or maybe tell me how to convert this string to binary data to I can try passing it in this way?
Thanks #identigral. This was one of the issues.
One major thing that helped me debug was going to setup->bulk data load jobs. If you click on a specific job, and hover over the "state message", it will give you the reason why a job failed. Although salesforce has an api for getting the failed job record here, which supposedly is supposed to return an error message, it did not work, which is why I felt kind of stuck, and led me to believe I wasn't passing in the csv correctly.
So I had a few errors:
Like identigral pointed out, I used "CLRF" as the line ending because I thought I was on windows, but since I type out the string myself in the code, I had to use "LF". I believe if I read in a csv file that I create using Excel, I would probably have to use "CLRF", although I haven't tested it yet.
Salesforce doesn't like the space in front of "Name__c", so although I had a field with that name on my object, it said "field Name__c" not found.
The documentation I linked said that after uploading the csv, "You should get a response that includes the job ID still in the Open state." However, that is not the case. The PUT request to upload the csv will have an empty request body and only return status 201 if the request was successful. This is found here: link
I realized this was the correct way as in this documentation, it gives an example of passing in data of type text/plain by doing data='Привет, Мир!', so I figured text/csv should be the same.
So the final code to send the csv that ended up working is as follows: (self.session is an instance of aiohttp.ClientSession() and I had already included the bearer token in the default headers when initializing the session):
csv_string = "Id,Name__c\n,\"Doe,John\""
headers = {'Content-Type': 'text/csv', 'Accept': 'application/json'}
async with self.session.put(upload_url, data = csv_string, headers = headers) as response:
assert response.status == 201 #data was successfully received.
The following was how I defined my when creating the job (replace MyObject__c with the API name of the object from salesforce):
body = {'object': 'MyObject__c',
'contentType': 'CSV',
'operation': 'upsert',
"lineEnding": "LF",
"externalIdFieldName": "Id" }
I was making slack api calls through python library slackclient which is a wrapper around slack api. However, for some cases I need to make conventional api calls also with url and get/post method. I was trying to open a direct message channel with another user by my bot. The documentation - https://api.slack.com/methods/im.open says to "Present these parameters as part of an application/x-www-form-urlencoded querystring or POST body. application/json is not currently accepted."
Now in python, I can write,
url = 'https://slack.com/api/im.open'
headers = {'content-type':'x-www-form-urlencoded'}
data = {'token':BOT_TOKEN, 'user':user_id, 'include_locale':'true','return_im':'true'}
r= requests.post(url,headers,data )
print r.text
The message I get is {"ok":false,"error":"not_authed"}
I know the message is "not authed" although I use my bot token and another user id, my hunch is that I'm sending the request in wrong format because I just wrote it some way reading the documentation. I'm not sure how to exactly send these requests.
Any help?
since the Content-Type header is x-www-form-urlencoded sending data in form of dictionary does not work. you can try something like this.
import requests
url = 'https://slack.com/api/im.open'
headers = {'content-type': 'x-www-form-urlencoded'}
data = [
('token', BOT_TOKEN),
('user', user_id),
('include_locale', 'true'),
('return_im', 'true')
]
r = requests.post(url, data, **headers)
print r.text
The second parameter in requests.post is used for data, so in your request you're actually posting the headers dictionary. If you want to use headers you can pass arguments by name.
r= requests.post(url, data, headers=headers)
However this is not necessary in this case because 'x-www-form-urlencoded' is the default when posting form data.
I looked many questions similar to my title but I have not found any that had same problem as me yet.
I did requests.post to post JSON to API restful server. Below is the snippet
import requests
def upload_data():
url = "http://127.0.0.1:8088/"
data = {"value":"abc123"}
response = requests.post(url, data=data)
print response.status_code, response.reason, response.text
upload_data()
And for the server side
from flask_restful import Api, Resource
from flask import request
class MyAPI(Resource):
def get():
pass
def post(self):
value = request.data['value']
response_object = {
'value':value
}
return response_object, 201
I was hoping to get the POST function to work by showing the result of 201 Created with
{
'value':'abc123'
}
But whenever I run the script, it gives me error saying that
value = request.data["value"]
TypeError: string indices must be integers, not str
I am sorry if this is a bad question but if anyone could show me what I have been missing in this script, I really appreciate it. Thank you.
That's because request data hasn't been parsed into a python dictionary. Were you perhaps thinking of
data = json.loads(request.data)
However please note that you are not actually posting a JSON body to your flask server. You are posting multipart formdata. So you may probably be looking for the answer posted by luoluo.
One the other hand if you really wanted to deal with json, The correct way to send json looks something like this:
requests.post(url, json=data)
And then the loads as suggested.
The request.data is a string, while request.values is a MultiDict.
You need update your code to :
value = request.values.get('value')
instead of
value = request.data['value']
According to the doc
args
A MultiDict with the parsed contents of the query string. (The part in the URL after the question mark).
form
A MultiDict with the parsed form data from POST or PUT requests. Please keep in mind that file uploads will not end up here, but instead in the files attribute.
values
A CombinedMultiDict with the contents of both form and args.
data
Contains the incoming request data as string in case it came with a mimetype Flask does not handle.
I would like to do a HTTP DELETE with python requests module that follows the API below;
https://thingspeak.com/docs/channels#create
DELETE https://api.thingspeak.com/channels/4/feeds
api_key=XXXXXXXXXXXXXXXX
I am using python v2.7 and requests module. My python code looks like this;
def clear(channel_id):
data = {}
data['api_key'] = 'DUCYS8xufsV613VX'
URL_delete = "http://api.thingspeak.com/channels/" + str(channel_id) + "/feeds"
r = requests.delete(URL_delete, data)
The code does not work because requests.delete() can only accept one parameter. How should the correct code look like?
You want
import json
mydata = {}
mydata['api_key'] = "Jsa9i23jka"
r = requests.delete(URL_delete, data=json.dumps(mydata))
You have to use the named input, 'data', and I'm guessing that you actually want JSON dumped, so you have to convert your dictionary, 'mydata' to a json string. You can use json.dumps() for that.
I don't know the API you are using, but by the sound of it you actually want to pass URL parameter, not data, for that you need:
r = requests.delete(URL_delete, params=mydata)
No need to convert mydata dict to a json string.
You can send the data params as #Eugene suggested, but conventionally delete requests only contains url and nothing else. The reason is that a RESTful url should uniquely identify the resource, thereby eliminating the need to provide additional parameters for deletion. On the other hand, if your 'APIKEY' has something to do with authentication, then it should be part of headers instead of request data, something like this.
headers = {'APIKEY': 'xxx'}
response = requests.delete(url, data=json.dumps(payload), headers=headers)
I dont want to use html file, but only with django I have to make POST request.
Just like urllib2 sends a get request.
Here's how you'd write the accepted answer's example using python-requests:
post_data = {'name': 'Gladys'}
response = requests.post('http://example.com', data=post_data)
content = response.content
Much more intuitive. See the Quickstart for more simple examples.
In Python 2, a combination of methods from urllib2 and urllib will do the trick. Here is how I post data using the two:
post_data = [('name','Gladys'),] # a sequence of two element tuples
result = urllib2.urlopen('http://example.com', urllib.urlencode(post_data))
content = result.read()
urlopen() is a method you use for opening urls.
urlencode() converts the arguments to percent-encoded string.
The only thing you should look at now:
https://requests.readthedocs.io/en/master/
You can use urllib2 in django. After all, it's still python. To send a POST with urllib2, you can send the data parameter (taken from here):
urllib2.urlopen(url[, data][, timeout])
[..] the HTTP request will be a POST instead of a GET when the data parameter is provided
Pay attention, that when you're using 🐍 requests , and make POST request passing your dictionary in data parameter like this:
payload = {'param1':1, 'param2':2}
r = request.post('https://domain.tld', data=payload)
you are passing parameters form-encoded.
If you want to send POST request with only JSON (most popular type in server-server integration) you need to provide a str() in data parameter. In case with JSON, you need to import json lib and make like this:
payload = {'param1':1, 'param2':2}
r = request.post('https://domain.tld', data=json.dumps(payload))`
documentation is here
OR:
just use json parameter with provided data in the dict
payload = {'param1':1, 'param2':2}
r = request.post('https://domain.tld', json=payload)`