Python 2 Zoho Post Error? - python

I am trying to add a lead to a Zoho CRM module with Python. I keep getting:
< response>< error>< code>4600< /code>< message>Unable to process your request. Please verify if the name and value is appropriate for the "xmlData" parameter.< /message>< /error>< /response>
from the server. I have no idea if I am posting correctly or if it is a problem with our Xml Data. I am using urllib and urllib2 to format the post request.
The post request looks like this.
url = ("https://crm.zoho.com/crm/private/xml/Leads/insertRecords?authtoken="
""+str(self.authToken)+"&scope=crmapi")
params = {"xmlData":self.xml}
data = urllib.urlencode(params)
request = urllib2.Request(url = url, data =data)
request.add_header("Content-Type",'application/xml')
response = urllib2.urlopen(request)

You cannot combine HTTP GET query parameters (ones in URL) and HTTP POST parameters.
This is limitation on the HTTP protocol level, not in Python or Zoho.
Most likely you are doing it wrong. Revisit Zoho documentation how it should be done.
Here is another old library doing Zoho + CRM, written in Python. You might want to check it for inspiration: https://github.com/miohtama/mfabrik.zoho

Related

How to send POST request with each payload on its own line using Python requests

I have to send a POST request to the /batch endpoint of : 'https://www.google-analytics.com'.
As mentioned in the Documentation I have to send the request to /batch endpoint and specify each payload on its own line.
I was able to achieve this using POSTMAN as follows:
My query is to make a POST request using Python's requests library
I tried something like this :
import requests
text = '''v=1&cid=43223523&tid=UA-XXXXXX-1&t=event&ec=aggregated_stats&ea=daily_kpi&el=bookmarks&ev=13
v=1&cid=43223523&tid=UA-XXXXXX-1&t=event&ec=aggregated_stats&ea=daily_kpi&el=upvotes&ev=65
v=1&cid=43223523&tid=UA-XXXXXX-1&t=event&ec=aggregated_stats&ea=daily_kpi&el=questions&ev=15
v=1&cid=43223523&tid=UA-XXXXXX-1&t=event&ec=aggregated_stats&ea=daily_kpi&el=postviews&ev=95'''
response = requests.post('https://www.google-analytics.com/batch', data=text)
but it doesn't works.
UPDATE
I Tried this and it works !
import http.client
conn = http.client.HTTPSConnection("www.google-analytics.com")
payload = "v=1&cid=43223523&tid=UA-200248207-1&t=event&ec=aggregated_stats&ea=daily_kpi&el=bookmarks&ev=13\r\nv=1&cid=43223523&tid=UA-200248207-1&t=event&ec=aggregated_stats&ea=daily_kpi&el=upvotes&ev=63\r\nv=1&cid=43223523&tid=UA-200248207-1&t=event&ec=aggregated_stats&ea=daily_kpi&el=questions&ev=11\r\nv=1&cid=43223523&tid=UA-200248207-1&t=event&ec=aggregated_stats&ea=daily_kpi&el=postviews&ev=23"
headers = {
'Content-Type': 'text/plain'
}
conn.request("POST", "/batch", payload, headers)
res = conn.getresponse()
But the question remains open, what's the issue with requests here.
You don't need to double-escape the newline symbol.
Moreover, you don't need the newline symbol at all for the multi-line string.
And also the indentations you put in your multi-line string are counted:
test = '''abc
def
ghi'''
print(test)
Here's an SO answer that explains this with some additional ways to make long stings: https://stackoverflow.com/a/10660443/4570170
Now the request body.
The documentation says
payload_data – The BODY of the post request. The body must include exactly 1 URI encoded payload and must be no longer than 8192 bytes.
So try uri-encoding your payload:
text = '''v=1&cid=43223523&tid=UA-XXXXXX-1&t=event&ec=aggregated_stats&ea=daily_kpi&el=bookmarks&ev=13
v=1&cid=43223523&tid=UA-XXXXXX-1&t=event&ec=aggregated_stats&ea=daily_kpi&el=upvotes&ev=65
v=1&cid=43223523&tid=UA-XXXXXX-1&t=event&ec=aggregated_stats&ea=daily_kpi&el=questions&ev=15
v=1&cid=43223523&tid=UA-XXXXXX-1&t=event&ec=aggregated_stats&ea=daily_kpi&el=postviews&ev=95'''
text_final = requests.utils.quote(text)
response = requests.post('https://www.google-analytics.com/batch', data=text_final)
Finally , I figured out the solution myself.
Updating for others help.
The problem was I was working on AWS Cloud9 and as mentioned in the documentation
Some environments are not able to send hits to Google Analytics directly. Examples of this are older mobile phones that can't run JavaScript or corporate intranets behind a firewall.
So we just need to include the User Agent parameter
ua=Opera/9.80
in each of our payloads
It works !

Netsuite REST Web Services API GET Request, Outside of Postman

Hi Stack Overflow community, thanks in advance for your help:
Question for Community:
Instead of reinventing the oauth wheel, are there any tips / best practices for creating my own oauth signature/nonce within my python GET requests for Netsuite's new API (REST Web Services; see below for context of question)? It seems that other folks who have been successful at this have done it through trial and error which is my plan as well, but ideally I'd like to have fewer errors and again, not reinvent the wheel. Any tips, tricks, ideas are greatly welcome. See context below
What:
Attempting to make a GET request using Netsuite's brand new REST API (REST Web Services). This is a different API than their SOAP/ RESTlets.
How:
Through writing Python script in Visual Studio Code. I am successful at making the request in Postman. I copied the code into Visual Studio Code that Postman used to make the successful GET request and received a 401 response (see below).
Problem Encountered:
I receive a 401 response, invalid login. There is no official Netsuite documentation on how make a successful interaction with this new REST API outside of Postman, so after reading through StackOverflow and other blogs/publications it seems that I need to create my own oauth_signature, oauth_timestamp, and oauth_nonce.
Postman GET Request Code:
import requests
url = "https://123456-sb1.suitetalk.api.netsuite.com/services/rest/query/v1/workbook/custworkbook12345/result"
payload = {}
headers = {
'Authorization': 'OAuth realm="123456_SB1",oauth_consumer_key="123456789101112131415",oauth_token="123456789101112131415",oauth_signature_method="HMAC-SHA256",oauth_timestamp="123456789",oauth_nonce="123456789",oauth_version="1.0",oauth_signature="123456789101112131415"',
'Cookie': 'NS_ROUTING_VERSION=LAGGING'
}
response = requests.request("GET", url, headers=headers, data = payload)
print(response.text.encode('utf8'))
Thanks in advance!
Thanks to Josh's recommendation (see comments to my original question) I successfully used oauthlib's oauth1 client to send a request in Visual Studio Code. The nonce and signature look a little different than what Postman shows in their code snippet, but it did work. For anyone attempting the same thing with Netsuite's REST Web Services I suggest going this route.
My code that sent a successful GET request:
import requests
import oauthlib.oauth1
import json
url = "https://12345-sb1.suitetalk.api.netsuite.com/services/rest/query/v1/dataset/custdataset1/result"
payload = {}
client = oauthlib.oauth1.Client('consumer key', client_secret='12345',
resource_owner_key='12345', resource_owner_secret='12345', realm='12345_SB1',signature_method="HMAC-SHA256")
url, headers, body = client.sign('https://4635201-sb4.suitetalk.api.netsuite.com/services/rest/query/v1/dataset/custdataset1/result')
response = requests.request("GET", url, headers=headers, data = payload)
print(response.text.encode('utf8'))
A Few Additional Helpful Notes -
I'm testing this in Netsuite Sandbox, hence the realm "12345_SB1". If
you aren't in sandbox you shouldn't need the underscore SB. Just use your account ID.
I'm pulling Netsuite Analytics Report, which at this time is still in
beta for the new API (REST Web Services).
I used the Python oauthlib that Josh recommended and I recommend you do the same, link here

Bad Request (400) error while trying to access REST API using requests in python

This error is so common that I found several hits on this error. However, couldn't find a solution to my problem.
I am trying to consume a REST API (not one of the publicly available ones) using requests module in Python. However, the specifications for the API consumption indicates that I call a POST method with URI, Content-type = 'application/xml' and body "<authCommand><userID> </userID><password> </password></authCommand>".
I tried this in the Python using requests:
r1 = requests.post('https://abc.360.net/rest/auth/1/login.xml',data= None, auth=('sdm#company.com','*********'), headers = {'content-type':'application/xml'})
When I run this, I receive a bad request error.
Is this the correct approach? Why am I receiving this error?
auth argument is to set Authorization header (basic http authentication by default). The API expects credentials in the body:
r = request.post(url, data=xml, headers={'Content-Type': 'application/xml'})
where xml=b"<authCommand><userID>sdm#company.com</authCommand>...".

Python httplib POST request and proper formatting

I'm currently working on a automated way to interface with a database website that has RESTful webservices installed. I am having issues with figure out the proper formatting of how to properly send the requests listed in the following site using python.
https://neesws.neeshub.org:9443/nees.html
Particular example is this:
POST https://neesws.neeshub.org:9443/REST/Project/731/Experiment/1706/Organization
<Organization id="167"/>
The biggest problem is that I do not know where to put the XML formatted part of the above. I want to send the above as a python HTTPS request and so far I've been trying something of the following structure.
>>>import httplib
>>>conn = httplib.HTTPSConnection("neesws.neeshub.org:9443")
>>>conn.request("POST", "/REST/Project/731/Experiment/1706/Organization")
>>>conn.send('<Organization id="167"/>')
But this appears to be completely wrong. I've never actually done python when it comes to webservices interfaces so my primary question is how exactly am I supposed to use httplib to send the POST Request, particularly the XML formatted part of it? Any help is appreciated.
You need to set some request headers before sending data. For example, content-type to 'text/xml'. Checkout the few examples,
Post-XML-Python-1
Which has this code as example:
import sys, httplib
HOST = www.example.com
API_URL = /your/api/url
def do_request(xml_location):
"""HTTP XML Post requeste"""
request = open(xml_location,"r").read()
webservice = httplib.HTTP(HOST)
webservice.putrequest("POST", API_URL)
webservice.putheader("Host", HOST)
webservice.putheader("User-Agent","Python post")
webservice.putheader("Content-type", "text/xml; charset=\"UTF-8\"")
webservice.putheader("Content-length", "%d" % len(request))
webservice.endheaders()
webservice.send(request)
statuscode, statusmessage, header = webservice.getreply()
result = webservice.getfile().read()
print statuscode, statusmessage, header
print result
do_request("myfile.xml")
Post-XML-Python-2
You may get some idea.

sending data to xml api of webservice

Im trying to write a python script that basically interacts with a webservice that uses an xml api. The request method is POST.
Usually I would write a request of the form request(url, data, headers) - however, in the case of an xml api it would not work. Also something like data.encode('utf-8') or urllib.urlencode(data) would not work as the data is not a dict.
In this case, data is xml so how am i supposed to sent it over?
[EDIT]
When I send a string of XML I get a urllib2.HTTPError: HTTP Error 415: Unsupported Media Type Exception. Is there any other way I'm supposed to send the data?
Also, the API I am using the Google Contacts API. I'm trying to write a script that adds a contact to my gmail account.
You probably need to set proper Content-Type header, for XML it would probably be:
application/xml
So something like this should get you going:
request = urllib2.Request( 'xml_api.example.com' )
request.add_header('Content-Type', 'application/xml')
response = urllib2.urlopen(request, xml_data_string)
Hope that helps :)

Categories