Uber API reports JSON is invalid for /requests/estimates endpoint - python

I have made a fork of the Uber Application for Heroku
My Fork: https://github.com/CuriosityGym/Python-Sample-Application
I have modified the original code and the /price URL to get me estimates of price for a specific product ID, using the /requests/estimates endpoint documented here https://developer.uber.com/docs/riders/references/api/v1.2/requests-estimate-post.
#app.route('/price', methods=['GET'])
def price():
"""Example call to the price estimates endpoint.
Returns the time estimates from the given lat/lng given below.
"""
url = config.get('base_uber_url') + 'requests/estimate'
params = {
"product_id": "83941b0d-4be1-4979-a9c0-f0af5ee2b89b",
"start_latitude": config.get('start_latitude'),
"start_longitude": config.get('start_longitude'),
"end_latitude": config.get('end_latitude'),
"end_longitude": config.get('end_longitude')
}
print params
print generate_ride_headers(session.get('access_token'))
response = app.requests_session.post(
url,
headers=generate_ride_headers(session.get('access_token')),
data=params
)
return render_template(
'results.html',
endpoint='price',
data=response.text,
)
Here is the snippet of my code which uses the 1.2 version of the Uber Api. Other end points are working fine, its this one that does not work.
The print statements print to the Heroku logs and this is the output
{'product_id': '83941b0d-4be1-4979-a9c0-f0af5ee2b89b', 'end_longitude': '72.8811862', 'start_latitude': '18.936404', 'end_latitude': '19.0822507', 'start_longitude': '72.832546'}
{'Content-Type': 'application/json', 'Authorization': 'Bearer KA.eyJ2ZXJzaW9uIjkgsdshdJpZCI6IkNmcjAvRzhrUUNPaDNhSnRsUVZ6QlE9PSIsImV4cGlyZXNfYXQiOjE1MTAzMjA3NzgsInBpcGVsaW5lX2tleV9pZCI6Ik1RPT0iLCJwaXBlbGluZV9pZCI6MX0.JDoDTgaYJitK8Rtr35C6gTh5IQc7-P4T7mGg_wOYXu0'}
The error Reported by the api is
{"message":"Unable to parse JSON in request body.","code":"invalid_json"}

You need to encode your json as a string. Luckily requests can do this for you or you can use json.dumps() to dump the object as a string.
Here are two examples:
Either do this:
import json
response = app.requests_session.post(
url,
headers=generate_ride_headers(session.get('access_token')),
data=json.dumps(params)
)
Or pass it as a kwarg json:
response = app.requests_session.post(
url,
headers=generate_ride_headers(session.get('access_token')),
json=params
)

Related

Spotify Web API not detecting body of POST request

I'm currently working on an app, one functionality of it being that it can add songs to the user's queue. I'm using the Spotify API for this, and this is my code to do so:
async def request():
...
uri = "spotify:track:5QO79kh1waicV47BqGRL3g" # temporary, can change later on
header = {'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': "{} {}".format(TOKEN_TYPE, ACCESS_TOKEN)}
data = {'uri': uri}
resp = requests.post(url="https://api.spotify.com/v1/me/player/queue", data=data, headers=header)
...
I've tried a lot of things but can't seem to understand why I'm getting Error 400 (Error 400: Required parameter uri missing).
so the Spotify API for the endpoint you're using suggests that the uri parameter required should be passed as part of the url, instead of as a data object.
Instead of data = {'uri': uri} can you please try adding your uri to the end of the url as such:
resp = requests.post(url="https://api.spotify.com/v1/me/player/queue?uri=?uri=spotify%3Atrack%3A5QO79kh1waicV47BqGRL3g", headers=header)
I also suggest using software like postman or insomnia to play around with the requests you send.

Zoho CRM API: Python request-based POST or GET authentication + insertion of contacts

The Task##
A django application that allows users to sign up and once the user clicks on the account activation link, Zoho CRM is receiving the data and a contact is created in the CRM section.
The Problem
I am currently working on an absolute masterpiece - the ZOHO API.
I am struggling to set up the native Python code that uses POST/GET requests.
Regarding the zcrmsdk 3.0.0, I have completely given up on this solution unless somebody can provide a fully functional example. The support simply blames my code.
The documentation I consulted:
https://www.zoho.com/crm/developer/docs/api/v2/access-refresh.html,
https://www.zoho.com/crm/developer/docs/api/v2/insert-records.html
Since the post request in postman API works fine I do not understand why it does not work in python code
My approach
Generate an self-client API code on: https://api-console.zoho.com/
Insert that code on Postman and retrieve the access or refresh token
Use this access token in an add_user_contact function that is defined in the documentation
It works! Response is success and it is in Zoho CRM
The permsissions scope I am using is: ZohoCRM.modules.contacts.ALL, ZohoCRM.users.ALL, ZohoCRM.modules.deals.ALL, ZohoCRM.modules.attachments.ALL, ZohoCRM.settings.ALL, AAAserver.profile.ALL
Picture of Post Man POST REQUEST
My own Code
def authenticate_crm():
"""
access to response object id:
response_object.get('data')[0].get('details').get('id')
"""
url = 'https://accounts.zoho.com/oauth/v2/token'
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
# one time self-client token here -
request_body = {
"code": "1000.aa8abec144835ab79b8f9141fa1fb170.8ab194e4e668b8452847c7080c2dd479",
"redirect_uri": "http://example.com/yourcallback",
"client_id": "1000.H95VDM1H9KCXIADGF05E0E1XSVZKFQ",
"client_secret": "290e505ec52685fa62a640d874e6560f2fc8632e97",
" grant_type": "authorization_code"
}
response = requests.post(url=url, headers=headers, data=json.dumps(request_body).encode('utf-8'))
if response is not None:
print("HTTP Status Code : " + str(response.status_code))
print(response.json())
I am essentially struggling to convert the Postman API request to a Python request to get the token as part of the workflow. What am I doing wrong here?
The documentation states: Note: For security reasons, pass the below parameters in the body of your request as form-data. (access-refresh link) but passing it in postman as form-data breaks the call completely.
According to their own documentation (which is convoluted, contradictory and full of outdated screenshots) the authentication key is needed only once.
Once the request from above runs, I would take the response in the third image and use the refresh key to add the contact.
I am also open to a solution with the SDK 3.0.0, if anybody can help.
I solved it!
I have changed this line:
response = requests.post(url=url, headers=headers, data=json.dumps(request_body).encode('utf-8'))
to this and added some return statement:
payload = '1000.6d9411488dcac999f02304d1f7843ab2.e14190ee4bae175debf00d2f87143b19&' \
'redirect_uri=http%3A%2F%2Fexample.com%2Fyourcallback&' \
'client_id=1000.H95VDM1H9KCXIADGF05E0E1XSVZKFQ&' \
'client_secret=290e505ec52685fa62a640d874e6560f2fc8632e97&'\
'grant_type=authorization_code'
response = requests.request(method="POST", url=url, headers=headers, data=payload)
if response is not None:
print("HTTP Status Code : " + str(response.status_code))
# print(response.text)
print(response.json())
# catch access and refresh token
at = response.json().get('access_token')
rt = response.json().get('refresh_token')
return at, rt
I do not understand why that is different but that fixed it and I could retrieve keys from ZOHO.

What is the best method to return smmry api request with block of text in json instead of url?

I am trying to write a function in python that returns the json from a request to the smmry API. I was able to get it working with the SM_URL request like this:
def summry():
API_ENDPOINT = "https://api.smmry.com"
API_KEY = "B..."
params = {
"SM_API_KEY":API_KEY,
"SM_URL":"https:..."
}
r = requests.get(url=API_ENDPOINT, params=params)
return r.json()
However, I am not sure how you would do this for passing in a block of text instead of a URL. I have tried making the request with sm_api_input=my_input but that returned an error of insufficient variables. I have also tried it with a POST request and got the same error.
If anyone is curious, this is how I solved the problem. Turns out I needed an Expect: 100-continue header and the sm_api_input is a separate post field instead of a get query.
def summry(text):
API_KEY = "B..."
API_ENDPOINT = "https://api.smmry.com"
data = {
"sm_api_input":text
}
params = {
"SM_API_KEY":API_KEY
}
header_params = {"Expect":"100-continue"}
r = requests.post(url=API_ENDPOINT, params=params, data=data, headers=header_params)
return r.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

Requests package and API documentation

I'm having trouble understanding where to add parameters defined by API documentation. Take BeeBole's documentation for example, which specifies that to get an absence by ID, the following request is required:
{
"service": "absence.get",
"id": "absence_id"
}
They provide only one URL in the documentation:
BeeBole is accepting HTTP POST resquests in a json-doc format to the following URL:
https://beebole-apps.com/api/v2
How would this be implemented in the context of Python requests? The following code I've tried returns 404:
import requests
payload = {
"service": "absence.get",
"id": "absence_id"
}
auth = {
"username": "API_token",
"password": "x"
}
url = "https://beebole-apps.com/api/v2"
req = requests.get(url, params=payload, auth=auth).json()
BeeBole is accepting HTTP POST resquests in a json-doc format to the following URL: https://beebole-apps.com/api/v2
The JSON document format here is the part you missed; you need to pass the information as a JSON encoded body of the request. The params argument you used only sets the URL query string (the ?... part in a URL).
Use
import requests
payload = {
"service": "absence.get",
"id": "absence_id"
}
auth = ("API_token", "x")
url = "https://beebole-apps.com/api/v2"
req = requests.get(url, json=payload, auth=auth).json()
The json= part ensures that the payload dictionary is encoded to JSON and sent as a POST body. This also sets the Content-Type header of the request.
I've also updated the API authentication, all that the auth keyword needs here is a tuple of the username and password. See the Basic Authentication section.
You may want to wait with calling .json() on the response; check if the response was successful first:
req = requests.get(url, json=payload, auth=auth)
if not req.ok:
print('Request not OK, status:', req.status_code, req.reason)
if req.content:
print(req.text)
else:
data = req.json()
if data['status'] == 'error':
print('Request error:', data['message'])
This uses the documented error responses.
From the site documentation it would appear that this particular vendor has chosen an unusual API. Most people use different endpoints to implement different operations, but BeeBole appears to implement everything off the one endpoint, and then selects the operation by examining the "service" key in the request data.
Try
response - request.post('https://beebole-apps.com/api/v2',
json={"service": "company.list"},
headers={"authorization": TOKEN)
From the documentation I can't guarantee that will put the request in the right format, but at least if it doesn't work it should give you some clue as to how to proceed. Establishing the correct value of TOKEN is described under "Authorization" in the BeeBole documentation.
It's an unusual way to offer an API, but it seems workable.

Categories