GCM get invalid tokens when sending to multiple devices at once - python

I'm trying to remove invalid GCM Tokens from my database after they failed in a broadcast request.
I send it via:
payload = {
"registration_ids": gcm_keys,
"data": messageData
}
headers = {
'Content-type': 'application/json',
'Authorization': Message_Broker.api_key
}
try:
return requests.post(Message_Broker.host, data=json.dumps(payload), headers=headers)
Lets say I try to send a message to:
gcm_keys = ['daöodaeöoijiö','12345','fwiorjpfwj'] # Lets pretend the second one is a valid token
From the content of the response object I get a dict like this:
response_results = [{u'error': u'InvalidRegistration'}, {u'registration_id': u'1234567', u'message_id': u'0:14339323424213768%540eeb39f9fd7aed'}, {u'error': u'InvalidRegistration'}]
To find out which tokens failed I made a set substraction with a list comprehension:
failed_keys = list(set(gcm_keys) - set([r.get('registration_id') for r in response_results]))
This should give me back only the tokens which produced an error.
My first question is, is there a more common way to do so or any kind of best practice?
Second question is, as you can see in the response_results and the gcm_keys, the valid token is not returned. Instead a kinda similar token is given back.
I did not find any on this. Why do I get a different token back?
-> Just found out that in case I get a different token back, I should replace the old one. That leads to another question. When I send to several tokens, how can I find out to which gcm token in the request this returned token belongs?
Is the order in the results always the same as in the request?

The response body's results parameter should have an array of objects that are listed in the same order as the request. Please refer here.

Related

JSON wrapped in NULL? [duplicate]

This question already has answers here:
What is JSONP, and why was it created?
(10 answers)
Django - Parse JSONP (Json with Padding)
(2 answers)
Closed last month.
I'm using the API of an affiliate network (Sovrn), expecting to retrieve a product's specification using the URL.
As per their documentation, I use:
url = 'URL-goes-here'
headers = {
"accept": "application/json",
"authorization": "VERY-HARD-TO-GUESS"
}
response = requests.get(url, headers=headers)
The code is working, the response I get is 200, the header contains the magical content-type application/json line
when I do
print(response.text)
I get
NULL({"merchantName":"Overstock","canonicalUrl":"URL goes here","title":"product name",...});
I tested for response type of response.text, it's <class 'str'> as expected. But when I try to process the response as json:
product_details = json.load(response.text)
I get an error message:
requests.exceptions.JSONDecodeError: [Errno Expecting value]
I'm new to JSON, but I assume the error is due to the outer NULL that the (seemingly valid) data is wrapped in.
After spending a few hours searching for a solution, it seems that I must be missing something obvious, but not sure what.
Any pointers would be extremely helpful.
That's clearly a bug in the API. Assuming it will be fixed after you complain, you could add a hack to your code
def sovrn_json_load_hack(json_text):
"""sovrn is returning invalid json as of (revision here)."""
if not json_text.startswith ("NULL("):
return json.loads(json_text)
else:
return json.loads(json_text[5:-2])
You can ignore NULL( at the beginning and ); at the end by using string slicing:
product_details = json.loads(response.text[5:-2])
Additionally, you should be using json.loads() as the content is a string.

Data sent with the requests.delete method is disregarded

While trying to connect to an API from Alpaca (a broker that accepts automated orders), I found that I was unable to send data with the requests.delete method. Here is some code:
def close_position(symbol, percentage, api_key=api_key, secret_key=secret_key, base_url=base_url):
data = {"percentage": percentage}
headers = {
"APCA-API-KEY-ID": api_key,
"APCA-API-SECRET-KEY": secret_key
}
url = f"{base_url}/v2/positions/{symbol}"
order = requests.delete(url, json=data, headers=headers)
return order.json()
This code is supposed to close (i.e., liquidate) a specified percentage of a position. However, it seems that the data sent using the delete method is disregarded; this function always closes my entire position instead of the specified percentage. Here is the documentation for the Alpaca API: https://alpaca.markets/docs/api-references/trading-api/positions/#close-a-position
I have also tried the data and params parameter and json.dumps(data), but to no avail.
Any idea how to send data with the requests.delete method would be appreciated.

Am I sending a this json data correctly using the python requests library?

I'm trying to send this json array to an API using request.post():
{
"insert": [
{
"data": "48bPRVkgvHwjG2VUTkPLaGazynZ6RxETuNGsYZNBrtb7ZkAUqY1NE2iGqoLd8EFsvhbDGW8gNb96Jce8fg2aiY8A5mbd8zf",
"tag": "0x1001"
}
]
}
I was told the json post has to be in an array by one of the devs at the site I'm posting to.
I also pored over these two examples in the API docs.1(edit emojiId section),2(adding an emoji id record)
What I tried so far is posting this dictionary:
{'insert': [{'data': '48bPRVkgvHwjG2VUTkPLaGazynZ6RxETuNGsYZNBrtb7ZkAUqY1NE2iGqoLd8EFsvhbDGW8gNb96Jce8fg2aiY8A5mbd8zf', 'tag': '0x1001'}]}
Using both of these post requests:
requests.post(base_url + '/emoji_id/🤘🐺🤘', json=dict_data, headers=headers)
requests.post(base_url + '/emoji_id/🤘🐺🤘', data=dict_data, headers=headers)
I then converted the dictionary to a string using
dict_data = json.dumps(dict_data, skipkeys=True, separators=(',', ':'))
and again sent it using both json and data.
Each returned a 405 error.
The next thing I tried is using the example this stack post to send a nested json. Here's my code for that attempt:
params = [{'data':'48bPRVkgvHwjG2VUTkPLaGazynZ6RxETuNGsYZNBrtb7ZkAUqY1NE2iGqoLd8EFsvhbDGW8gNb96Jce8fg2aiY8A5mbd8zf','tag':'0x1001'}]
# Tried above both with [ ] on outside making it a list and without
payload = {'insert': json.dumps(params, skipkeys=True, separators=(',', ':'))}
requests.post(base_url + '/emoji_id/🤘🐺🤘', json=payload, headers=headers)
Again, I used both json=payload and data=payload and again I tried it both as a dictionary and converting to a string using the same json.dumps method as above. Same as before each returned a 405 response.
My question is, am I using request.post() correctly in at least one of these attempts? If so, I must be missing something about what the API expects and can start down that rabbit hole.
#ewong nailed it. I didn't realize I had to use the patch method instead of the post method.
So my issue was fixed using:
requests.patch(base_url + '/emoji_id/🤘🐺🤘', json=dict_data, headers=headers)
instead of request.post. The difference between the two still seems subtle to me at this point but the example given in the API docs clearly show a patch method being used and that's what worked.

Mapbox API PUT Datasets Feature return "Provide a single Feature to insert"

I am trying to add a feature to the Dataset via Mapbox API using Python. I'm following this instruction https://docs.mapbox.com/api/maps/#update-a-dataset but keep getting this error:
{'message': 'Provide a single Feature to insert'}
The code looks like this:
rs = []
dictionary = {
"id":1,
"type":"Feature",
"properties":{},
"geometry":{"coordinates":[-83.750246, 42.269375],"type":"Point"}}
url = "https://api.mapbox.com/datasets/v1/voratima/"+dataset+"/features/1?access_token="+access_token
rs.append(grequests.put(url, data=dictionary, hooks = {'response' : do_something}))
grequests.map(rs, exception_handler=exception_handler)
I've tried the following but none of them work:
using requests instead of grequests
wrapping the dictionary with json.dumps()
changing the put parameter from data=dictionary to json=dictionary
Making sure the id for both data and URL are set to 1.
Postman of the exact same request does not have the error. What am I missing?
Given a dataset with dataset ID dataset exists, your request body looks ok.
Please add the header
headers = {'Content-type': 'application/json'}
Also can you check if you meet these specs:
This should be one individual GeoJSON feature, not a GeoJSON
FeatureCollection. If the GeoJSON feature has a top-level id property,
it must match the feature_id you use in the URL endpoint.
It turns out I forgot the header. Thanks to Mortiz for pointing that out. After the update I got
<Response [400]> {'message': 'Unexpected token i'}
That's because I need to wrap the dictionary inside json.dumps(). Then the error became
<Response [422]> {'message': 'Request URI does not match feature id'}
That's because the id in the dictionary has to be a string i.e. "id":"1" not "id":1. Here's the code that works:
rs = []
dictionary = {
"id":"1",
"type":"Feature",
"properties":{},
"geometry":{"coordinates":[-83.750246, 42.269375],"type":"Point"}}
headers = {'Content-type': 'application/json'}
url = "https://api.mapbox.com/datasets/v1/voratima/"+dataset+"/features/1?access_token="+access_token
rs.append(grequests.put(url, data=json.dumps(dictionary), headers=headers, hooks = {'response' : do_something}))
grequests.map(rs, exception_handler=exception_handler)

Blockchain info wallet check payment

i am trying to create bill for payment and send to my customer via telegram bot:
i am using blockchain API V2-https://blockchain.info/api/api receive .my code is:
xpub='***'
keyk='02e57f1***'
url='https://api.blockchain.info/v2/receive?xpub='+str(xpub)+'&callback=https%3A%2F%2Fdoors03.ru&key='+keyk
x=requests.get(url)
r=x.json()
r=r['address']
r -is an adress wich was made.
i am sending it to my costumer(by the way is there any way to send adress with exact sum for pay ) . After i want to check is payment was recieved:
data={ "Content-Type": "text/plain","key":keyk,"addr":r,"callback":"https%3A%2F%2Fdoors03.ru","onNotification":"KEEP", "op":"RECEIVE"}
r = requests.post(url, data=data)
and this is the response - u'{\n "message" : "Internal handlers error"\n}'
what i am doing wrong ? how to check payments ? how to send address with exact sum of btc or ethereum ?
Sorry, i don't have enough reputation to post a comment, so this is
the only option i have. #egorkh have you solved this problem? Maybe
you have received explanation from blockchain.info support? I have
sent them a question about that, but they are answering for too long.
UPDATE: Finally, i have found solution.
In my case, reason of "Internal handlers error" message is in a wrong interpretation of their API.
As they haven't implemented balance_update request in their java-api, i did it on my own and i did it in wrong way.
I have put this parameters:
{"key":keyk,"addr":r,"callback":"https%3A%2F%2Fdoors03.ru","onNotification":"KEEP", "op":"RECEIVE"}
as post parameters, like in other methods they have provided in api. In those methods parameters are URLEncoded like you did with callback link. But...
In this HTML request they must be sent as plain text in json format without any special encoding, like that:
Map<String, String> params = new HashMap<String, String>();
params.put("addr", address);
params.put("callback", callbackUrl);
params.put("key", apiCode);
params.put("onNotification", keepOnNotification? "KEEP" : "DELETE");
params.put("confs", Integer.toString(confirmationCount));
params.put("op", StringUtils.isBlank(operationType) ? "ALL" : operationType);
//parse parameters map to json string(that's optional: you can write it directly as string)
String body = new Gson().toJson(params);
if (requestMethod.equals("POST")) {
byte[] postBytes = body.getBytes("UTF-8");
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "text/plain");
conn.setRequestProperty("Content-Length", String.valueOf(postBytes.length));
conn.getOutputStream().write(postBytes);
conn.getOutputStream().close();
}
The main reason of your error may be that you put "Content-Type": "text/plain" in data object (, and maybe encoded callback url) .

Categories

Resources