I have this P2P python code, and I am trying to send a POST request from it to flask:
On my P2P side I have:
...
for reply in con:
jsonData = json.loads(reply)
print(jsonData)
print(type(jsonData) is dict, tuple)
data = urlencode(jsonData)
print(data + " : urlencode")
data = data.encode()
print(data.__class__)
req = urllib.request.Request("http://0.0.0.0:5000/validate", data)
response = urllib.request.urlopen(req)
#res = response.read()
print(response.read().decode('utf8') + " : response in alice")
For my flask code I have:
#app.route('/validate', methods=['POST'])
def validate():
print(request.args)
request args is always output as:
ImmutableMultiDict([])
The output for the P2P side is:
{'index': 2043, 'message': 'New Block Forged', 'previous_hash': 'fa4a49cd092869db788490e79a933e7a45107ce513523500e5cd9c85e25426de', 'proof': 168158, 'transactions': [{'amount': 1, 'recipient': '6760d061731c493e94897164c2362476', 'sender': '0'}]}
True <class 'tuple'>
index=2043&message=New+Block+Forged&previous_hash=fa4a49cd092869db788490e79a933e7a45107ce513523500e5cd9c85e25426de&proof=168158&transactions=%5B%7B%27amount%27%3A+1%2C+%27recipient%27%3A+%276760d061731c493e94897164c2362476%27%2C+%27sender%27%3A+%270%27%7D%5D : urlencode
<class 'bytes'>
{
"add": true
}
: response in alice
As you can see, the data for urllib.request.urlopen looks correct. Why isn't it getting through to the flask side?
You are making the POST request to validate endpoint. And request.args is only return the url querystring. So the real data will be available in request.form.
Answer
Please make the GET request... so data will be available in request.args
data = urllib.parse.urlencode(json_data)
url = 'http://localhost:5000?{}'.format(data)
with urllib.request.urlopen(url) as response:
pass
Related
I have been attempting to solve this far too longer than id like to admit, I think the problem is how the data is being parsed with json and being interoperated via the API, as I do not have the same issue with the first function, but run into it with the second. Any help will be great.
import urllib, requests, json
def generateUserKey(username, password):
global devKey
return urllib.request.urlopen("https://pastebin.com/api/api_login.php",
urllib.parse.urlencode({"api_dev_key": devKey, "api_user_name": username, "api_user_password": password}).encode()).read()
def paste(userKey, text):
global devKey
datA = json.dumps({"api_dev_key": devKey, "api_paste_code": text, "api_user_key": userKey, "api_paste_name": "lol", "api_paste_format": "none", "api_paste_private": int(1), "api_paste_expire_date": "10M" })
resp = requests.post(url="https://pastebin.com/api/api_post.php", json=datA, data=datA)
print(resp.text)
key = generateUserKey(devKey, userName, passWord)
print(key)
paste(key, testString)
when ran I generate the following:
c0ce26a1c46d5fff3a254e519003ebb0
Bad API request, invalid api_dev_key
None
the dev key isnt invalid as its being used in the previous function to login and obtain a session key, so this is where I am stuck. Any help?
this could help:
import requests # see https://2.python-requests.org/en/master/
import json
def generateUserKey(data):
login = requests.post("https://pastebin.com/api/api_login.php", data=data)
print("Login status: ", login.status_code if login.status_code != 200 else "OK/200")
print("User token: ", login.text)
return login.text
def paste(data):
r = requests.post("https://pastebin.com/api/api_post.php", data)
print("Paste send: ", r.status_code if r.status_code != 200 else "OK/200")
print("Paste URL: ", r.text)
key = 'your key'
text = "hi"
t_title = "title of paste"
login_data = {
'api_dev_key': key,
'api_user_name': 'username',
'api_user_password': 'password'
}
data = {
'api_option': 'paste',
'api_dev_key': key,
'api_paste_code': text,
'api_paste_name': t_title,
'api_user_key': None,
# 'api_paste_expire_date': 'see_https://pastebin.com/api', # optional
# 'api_paste_private': 1, # 0 = public, 1 = unlisted, 2 = private
'api_user_key': generateUserKey(login_data)
# see_https://pastebin.com/api fro all the other arguments you can add
}
# if your data is already in json format, you can use json.dumps(data)
# data = json.dumps(data) # and now its a dict, and it can be feed to the requests.post
paste(data)
if you have any questions don't hesitate to ask
I have a template for a Python function that calls an API and returns data. I'd like to run load testing against that API using locust.
import requests
proxies = {"http" : None,
"https" : None}
verify = "/data/certs/abc123.crt"
def call_api(par1, par2, par3):
r = requests.post(url = 'https://ABCD123.XYZ.QWERTY:9010/public/api/v1/ABC_TEST/query',
json = {"par1" : par1, "par2" : par2, "par3" : par3}, verify = verify, proxies = proxies)
return r
How could I translate this into a locust class?
I do it this way:
# prepare the headers to send to the remote host
headers = {"key":"value",
"key":"value"}
# prepare the data for the POST body
data = {"key":"value",
"key":"value"}```
with connection_object.client.post(url, headers=headers,
json=data, name=task_name, catch_response=True) as response:
# convert the response to JSON
msg = json.loads(response.content.decode('utf-8'))
if response.status_code == 200:
# we got a 200 OK
response.success()
else:
response.failure("failure text")
In this example, this code runs in a separate function called from the UserBehavior class, so connection_object is "self" if you are doing this inside the task in the class.
In your example though, change
r = requests.post(url = 'https://ABCD123.XYZ.QWERTY:9010/public/api/v1/ABC_TEST/query',
json = {"par1" : par1, "par2" : par2, "par3" : par3}, verify = verify, proxies = proxies)
to
class UserBehavior(SequentialTaskSet):
#task()
def task1(self):
r = self.client.post('https://ABCD123.XYZ.QWERTY:9010/public/api/v1/ABC_TEST/query',
json = {"par1" : par1, "par2" : par2, "par3" : par3},
verify = verify, proxies = proxies)
I am sure you have seen this, which shows "get", but not "post". If you are unfamiliar with the requests library, it can get confusing.
Hope that helps!
1) I require a function which should publish a post with the given message and photo.
One can use the page ID and access tokens provided in self.page_id and self.page_access_token
def __init__(self):
self.page_id = Facebook.get_access_token('FACEBOOK_PAGE_ID')
self.page_access_token = Facebook.get_access_token('FACEBOOK_PAGE_ACCESS_TOKEN')
2) To find which API to hit, check out developer section of the Facebook API: https://developers.facebook.com/docs/graph-api/reference/page/photos/#example-2
3) The function should not return anything.
def publish_photo_msg(self, message, image_url):
#your code here
return
Please help.
python
params = (
('access_token', self.page_access_token),
)
Next, let us fix the data dictionary:
python
data = {
'url': image_url,
'caption': 'this is the caption'
}
Now, let’s proceed to the URL. There are many ways to set this. Here is one way:
python
url = 'https://graph.facebook.com/v5.0/' + self.page_id + '/photos?access_token=' + self.page_access_token
Since we have stored the access_token in the params tuple, let’s make use of it in the requests.post() call.
python
url = 'https://graph.facebook.com/v5.0/' + self.page_id + '/photos'
response = requests.post(url=url, params=params, data=data)
Lastly, you can also verify if your requests.post() call was successful by checking the value of the response variable:
python
print response.status_code, response.json()
For easy reference, here is the full implementation of the publish_photo_msg function with all the suggestions incorporated:
python
params = (
('access_token', self.page_access_token),
)
data = {
'url': image_url,
'caption': message
}
url = 'https://graph.facebook.com/v5.0/' + self.page_id + '/photos'
response = requests.post(url=url, params=params, data=data)
print(response.status_code, response.json())
I need to send POST request from one Django app to another under the same project. The request arrives, but without POST data.
Why is that? And how to send POST data properly?
Sender part, app 1 view:
def get_project_data(request):
if request.method == "POST":
if request.is_ajax():
response = etl_post('get_data', [request.user.project.id], request.POST)
def etl_post(path, identifiers=None, post_data=None):
def date_handler(obj):
if hasattr(obj, 'isoformat'):
return obj.isoformat()
else:
raise TypeError
json_data = json.dumps(post_data, default=date_handler) if post_data else None
return _request(path, identifiers, json_data)
def _request(path, identifiers=None, post_data=None, method=None):
data = None
try:
url = urlparse.urljoin(settings.ETL_WEB_API_URL, path)
if identifiers is not None:
for o in identifiers:
url += "/" + str(o)
if post_data:
url += "/"
request = urllib2.Request(url, data=post_data)
request.add_header("Content-Type", "application/json")
request.add_header("X-ETL-Authorization", settings.ETL_WEB_API_KEY)
if method:
request.get_method = lambda: method
result = urllib2.urlopen(request)
data_str = result.read()
if result.getcode() == 200:
data = json.loads(data_str)
else:
logger.error("Unexpected response %s" % result)
except Exception as e:
logger.exception(e.message)
return data
Also, I tried result = urllib2.urlopen(request, data=post_data), no success.
post_data example:
{"project_id": "nYhRTAmGkkHSlLr8BfPR", "project_name": "rocket-launch", "salt": "805b2892c16369275eerec4dd401f5f", ...}
(Pdb) type(post_data)
<type 'str'>
Receiver part, app 2 view:
#csrf_exempt
def get_project_data(request, trust_id):
if request.method == 'POST':
pdb.set_trace()
The arrived message:
(Pdb) request
<WSGIRequest: POST '/pipeline/get_project_data/2/'>
(Pdb) request.POST
<QueryDict: {}>
You're sending JSON, not form-encoded data. That is found in request.body, not request.POST.
I must say though, if these two apps are in the same project there are much easier ways of sending data between them than by making HTTP requests.
I want to send a PUT request with the following data structure:
{ body : { version: integer, file_id: string }}
Here is the client code:
def check_id():
id = request.form['id']
res = logic.is_id_valid(id)
file_uuid = request.form['file_id']
url = 'http://localhost:8050/firmwares'
r = requests.put(url = url, data = {'body' : {'version': id, 'file_id': str(file_uuid)}})
Here is the server code:
api.add_resource(resources.FirmwareNewVerUpload, '/firmwares')
class FirmwareNewVerUpload(rest.Resource):
def put(self):
try:
args = parser.parse_args()
except:
print traceback.format_exc()
print 'data: ', str(args['body']), ' type: ', type(args['body'])
return
The server prints:
data: version type: <type 'unicode'>
And this result is not what I want. Instead of inner dictionary I got a string with name of one dictionary key. If I change 'version' to 'ver'
r = requests.put(url = url, data = {'body' : {'ver': id, 'file_id': str(file_uuid)}})
server prints
data: ver type: <type 'unicode'>
How to send a dictionary with inner dictionary?
Use json= instead of data= when doing requests.put and headers = {'content-type':'application/json'}:
r = requests.put(url = url,
json = {'body' : {'version': id, 'file_id': str(file_uuid)}},
headers = {'content-type':'application/json'})
In official doc you found a topic called More complicated POST requests
There are many times that you want to send data that is not form-encoded. If you pass in a string instead of a dict, that data will be posted directly.
>>> import json
>>> url = 'https://api.github.com/some/endpoint'
>>> payload = {'some': 'data'}
>>> r = requests.post(url, data=json.dumps(payload))
Maybe convert your data to JSON could be a good approach.
import json
def check_id():
id = request.form['id']
res = logic.is_id_valid(id)
file_uuid = request.form['file_id']
url = 'http://localhost:8050/firmwares'
payload = {'body' : {'version': id, 'file_id': str(file_uuid)}}
r = requests.put(url=url, data=json.dumps(payload))