Micropython POST request body empty - json

i have a server with POST e REST services. Using micropython i need to perform POST request.
GET queries arrive at the REST services and respond correctly using the following format:
s.send(b"GET /sensordata/premises HTTP/1.1\r\nHost:XX.XXX.XXX.XXX\r\n" + "Accept: application/json\r\n\r\n")
but for the POST looks like the request arrived to server, but the body is empty. For some reason the JSON body of the request is not interpreted in a correct way.
from network import WLAN
import socket
import machine
import time
import struct
import json
import pycom
wlan = WLAN(mode=WLAN.STA)
wlan.connect("*****", auth=(WLAN.WPA2, "*****"), timeout=5000)
while not wlan.isconnected():
machine.idle()
print("Connected to WiFi\n")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
url = 'XX.XXX.XXX.XXX'
sockaddr = socket.getaddrinfo(url, 80) [0][-1]
s.connect(sockaddr)
print('socket connected')
httpreq = b'POST /sensordata/insertrecords HTTP/1.1 \r\n Host:XX.XXX.XXX.XXX \r\n' + 'Accept: application/json \r\n' + 'Content-Type: application/json\r\n' + ' {\"node_id\":\"1\",\"value\":[{\"measure_time_stamp\":\"2020-10-06T09:25:43\",\"temp\":\"14\",\"humidity\":\"75\",\"ph1\":11,\"ph2\":12,\"ph3\":13}]}\r\n\r\n'
s.send(httpreq)
time.sleep(1)
rec_bytes = s.recv(4096)
print("RESPONSE = " + str(rec_bytes))
print('end')
s.close()

Are you aware of the urequests library? It's an HTTP client library inspired by the popular Python requests. A POST request is simply:
import urequests
r = urequests.post('https://your/endpoint')

Related

What is the equivalent of this Curl command in python3?

Should only be done with python3.
As i am not familiar with python3 i would like a full answer
and not just a snippet. Thank you if you take this into consideration!
curl -s "http://kodi:kodi#192.168.1.10:8080/jsonrpc?Base" -H 'Content-Type: application/json' --data '[{"jsonrpc":"2.0","method":"Player.GetProperties","params":[1,["time"]],"id":17},{"jsonrpc":"2.0","method":"Player.GetItem","params":[1,["file"]],"id":18}]'
this is what I get for the curl command:
[{"id":17,"jsonrpc":"2.0","result":{"time":{"hours":0,"milliseconds":597,"minutes":44,"seconds":53}}},{"id":18,"jsonrpc":"2.0","result":{"item":{"file":"smb://192.168.1.10/#.mkv","id":340,"label":"The Expendables 3","type":"movie"}}}]
from which I would get the values of "file", "hours", "minutes", and "seconds"
in front of hours, minutes, and seconds, if the number is 0-9 then put a 0 in front of it and save it in a .txt file
the .txt file should look like this:
smb://192.168.1.10/#.mkv
004453
exaple 2.
smb://192.168.1.10/#.mkv
010703
example 3.
smb://192.168.1.10/#.mkv
025547
bash solution, and more information here:
I got very good answers to my last question about this in bash
(if it might help you, here are complete solutions in awk or jq)
but, now i have to move to python3..
Thanks in advance for any help!
Edit3:
I finally succeeded in extracting the values.
how can this be further filtering?
to get it as shown in the example below?
>>> import json
>>> import base64
>>> from urllib.request import Request, urlopen
>>>
>>> credentials = b'kodi:kodi'
>>> encoded_credentials = base64.b64encode(credentials)
>>> authorization = b'Basic ' + encoded_credentials
>>>
>>> headers = { 'Content-Type': 'application/json', 'Authorization': authorization }
>>> url = 'http://192.168.1.10:8080/jsonrpc'
>>> data = [{"jsonrpc":"2.0","method":"Player.GetProperties","params":[1,["time"]],"id":17},{"jsonrpc":"2.0","method":"Player.GetItem","params":[1,["file"]],"id":18}]
>>>
>>> json_data = json.dumps(data)
>>> post_data = json_data.encode('utf-8')
>>> request = Request(url, post_data, headers)
>>> result = urlopen(request)
>>> print(result.read())
b'[{"id":17,"jsonrpc":"2.0","result":{"time":{"hours":0,"milliseconds":914,"minutes":52,"seconds":59}}},{"id":18,"jsonrpc":"2.0","result":{"item":{"file":"smb://192.168.1.10/n filmek 720p/The.Expendables.3.2014.Hybrid.READ.NFO.Extended.720p.BluRay.DTS.x264.HuN-TRiNiTY/theexpendables3.720p.hybrid.ex-trinity.mkv","id":340,"label":"The Expendables 3","type":"movie"}}}]'
which I would like to filter further for this:
smb://192.168.1.10/#.mkv
0
52
59
and I would like to "convert" it to this
smb://192.168.1.10/#.mkv
005259
import json
import base64
import requests
credentials = b'kodi:kodi'
encoded_credentials = base64.b64encode(credentials)
authorization = b'Basic ' + encoded_credentials
headers = { 'Content-Type': 'application/json', 'Authorization': authorization }
url = 'http://192.168.1.10:8080/jsonrpc?Base'
data = [
{"jsonrpc":"2.0","method":"Player.GetProperties","params":[1,["time"]],"id":17},
{"jsonrpc":"2.0","method":"Player.GetItem","params":[1,["file"]],"id":18}]
response = requests.post(url, headers=headers, data=json.dumps(data))
result = response.json()
h,m,s = map(int, [result[0]['result']['time'][val] for val in ['hours','minutes','seconds']])
time = f'{h:02}{m:02}{s:02}'
print(result[1]['result']['item']['file'],time, sep='\n', file=open("c:\\kodi\\save.txt", "w"))
save.txt
smb://192.168.1.10/#.mkv
005259

AWS Lambda verify requests from Slack

I have the following Python code in AWS Lambda to verify if an event received is indeed from Slack:
import hmac
import json
def verifySignature(header,body):
h = hmac.new(key=os.getenv('sign_secret').encode(), \
msg=f'v0:{header.get("X-Slack-Request-Timestamp")}:{body}'.encode(), \
digestmod="sha256")
result = hmac.compare_digest('v0='+h.hexdigest(),header.get('X-Slack-Signature'))
print('v0='+h.hexdigest(),header.get('X-Slack-Signature'))
return result
def lambda_handler(event, context):
body = json.loads(event.get('body'))
if verifySignature(event.get('headers'),body):
do_something()
Slack's authentication protocol is outlined here. However, I keep getting mismatching signatures (result == False). Does anyone know why?
There is a high chance the issue is coming from the encoding / decoding. There is pip package to verify the slack signature.
But the verification code is simple:
import hashlib
import hmac
def verify_slack_signature(slack_post_request, slack_signing_secret):
slack_signing_secret = bytes(slack_signing_secret, 'utf-8')
slack_signature = slack_post_request['headers']['X-Slack-Signature']
slack_request_timestamp = slack_post_request['headers']['X-Slack-Request-Timestamp']
request_body = slack_post_request["body"]
basestring = f"v0:{slack_request_timestamp}:{request_body}".encode('utf-8')
my_signature = 'v0=' + hmac.new(slack_signing_secret, basestring, hashlib.sha256).hexdigest()
return hmac.compare_digest(my_signature, slack_signature)

Different ways of reading data from s3 bucket using boto3

I'm trying to read some json file from s3 bucket and then trying to post the data into rds and redshift(using a post api developed/intended for that).
I approached to do this in 2 ways using boto3. Below are those:
1st way:
import boto3
import json
import requests
url = 'xxxx.us-east-1.elb.amazonaws.com/v1'
headers = {'content-type': 'application/json', 'Host': 'development.my.dns.com'}
endpoint = url+'/my/post/endpoint'
s3_client = boto3.client("s3")
fileObj = s3_client.get_object(Bucket='my-bucket-name', Key='my-key-name'])
data = fileObj['Body'].read().decode('utf-8')
with requests.request('POST', endpoint, data=data, headers=headers, auth=(username, pwd), verify=False, stream=True) as r:
print("Status Code:",r.status_code)
2nd way:
import boto3
import json
import requests
url = 'xxxx.us-east-1.elb.amazonaws.com/v1'
headers = {'content-type': 'application/json', 'Host': 'development.my.dns.com'}
endpoint = url+'/my/post/endpoint'
s3_res = boto3.resource('s3')
contentObj = s3_res.Object('my-bucket-name', 'my-key-name')
fileContent = contentObj.get()['Body'].read().decode('utf-8')
data = json.dumps(json.loads(fileContent))
with requests.request('POST', endpoint, data=data, headers=headers, auth=(username, pwd), verify=False, stream=True) as r:
print("Status Code:",r.status_code)
Basically everything is same(url, endpoint, headers, requests.request) and type(data) is <class 'str'> in both the approaches. But the status codes are always different.
The 2nd way gives Status Code: 200. But the 1st way gives Status Code: 413 or Status Code: 502 randomly
Can any one please explain why is it this way? what's different in the above two approaches? I'm trying to understand what's going on when boto3 read() the data differently.

How do I make a cURL request to zomato api?

I just began exploring APIs. This is my code so far. For locu API this works but for Zomato they use curl header request which I don't know how to use. Could someone guide or show me how?
import json
import urllib2
Key = 'Zomato_key'
url = 'https://developers.zomato.com/api/v2.1/categories'
json_obj = urllib2.urlopen(url)
data = json.load(json_obj)
print data
By looking at the Zomato API docs, it seems that the parameter user-key has to be set in the header.
The following works:
import json
import urllib2
Key = '<YOUR_ZOMATO_API_KEY>'
url = "https://developers.zomato.com/api/v2.1/categories"
request = urllib2.Request(url, headers={"user-key" : Key})
json_obj = urllib2.urlopen(request)
data = json.load(json_obj)
print data
If you want a more elegant way to query APIs, have a look at requests module (you can install using pip install requests).
I suggest you the following:
import json
import requests
Key = <YOUR_ZOMATO_API_KEY>'
url = "https://developers.zomato.com/api/v2.1/categories"
if __name__ == '__main__':
r = requests.get(url, headers={'user-key': Key})
if r.ok:
data = r.json()
print data
NB: I suggest you remove your Key from StackOverflow if you care about keeping it to yourself.
this didn't work for me can u suggest some other method for me.
-->the code when tried to compile is taking long time and returning an traceback error in request method that is in built
but curl command is working
curl -X GET --header "Accept: application/json" --header "user-key: c5062d18e16b9bb9d857391bb32bb52f" "https://developers.zomato.com/api/v2.1/categories"

How to call a REST API using Python using json request/response- Crucible Development

I am a newbie to python and am trying to create a script to login to crucible and use the token to pass to other services.
1) I am able to make a xml request and get a response but as soon as I pass the headers to my conn.request it says HTTP Error 415, unsupported Media Type.
I have done quiet a bit of research on this topic and found out that the rest API might not be supporting the json reques, but Crucible says that there API supports json so seems to be some other issue,
2) when trying to pass the args generated using feauth the auth token is not getting used , for now I have appended it to url and it works.
Please help me with the same , below is my script
import httplib
import urllib
import json
from xml.etree.ElementTree import XML
import xml.dom.minidom
conn = httplib.HTTPSConnection("fisheye")
args=urllib.urlencode({'userName':'UNAME', 'password':'PWD'})
headers={'content-type':'application/json', 'accept':'application/json'}
#headers={'Authorization' : 'Basic %s' % base64.b64encode("username:password")}
r1 = conn.request("post", "/rest-service/auth-v1/login", args)
#status = r1[u'headers']['status']
#conn.connect()
r2 = conn.getresponse()
print r1,r2.status,r2.reason,r2
r3=r2.read()
print(r3)
r4=str(r3)
print r4
data = XML(r4).find("token").text
print data
# data1=urllib.quote_plus(data, safe=":")
# print data1
args=urllib.urlencode({'FEAUTH':data}).replace("%3A", ":")
print "args is", args
#args={}
req = conn.request("get","/rest-service/reviews-v1")
r3 = conn.getresponse()
status = r3.status
print "the url is"#, r3.getheader('Location')
url=r3.getheader('location', '')
print url
url1=r3.msg#.dict['location']
print url1
#print req.url
#print req.get_method()
print dir(req) # list lots of other stuff in Request
print "after sending open review request"
print r3
print req,r3.status,r3.reason,r3
r4=r3.read()
print(r4)
r5=str(r4)
print r5
# json_ob=json.loads(r3.read())
# print json_ob
I was able to resolve the issue by
1) removing the Content-Type from the headers and changed the accept to Accept(sentence cased).
2) The login request was a get request and hence it supports data transfer by URL append, it is only for post request that we can pass an argument.
In the header of the request, try to specify the media type:
headers = { 'Content-Type' : 'application/json' }
req = urllib2.Request(url, headers=headers)