I am working with the django framework. I'm trying to send a post request with token using the requests package but it doesn't work. the status code of the request is 200.Here is my code:
def modifier_periode_push(request):
url = "ip_addr/openapi/device"
option1,option2,option3 = "040A0001","041E0001","043C0001"
headers = {
"Accept-Encoding":"gzip","Content-Length":"286","Content-Type":"application/json","Token":"xxxxxxxxx",
"User-Agent":"python-requests/2.26.0"
}
if request.is_ajax() and request.method == "POST":
if request.POST["periode"] == "10":
payload = convertir_en_hexa(option1)
elif request.POST["periode"] == "30":
payload = convertir_en_hexa(option2)
else:
payload = convertir_en_hexa(option3)
data = {
"devEUI":request.POST["devEUI"],
"confirmed":False,
"fPort":int(request.POST["fPort"]),
"data":payload
}
try:
**req = requests.post(url, headers=headers, data=data)**
print(req.status_code)# returns 200
except:
print("Erreur")
return HttpResponse("ok")
else:
return HttpResponse("Requete non authorisée")
I have got this message {'code': 1003, 'msg': 'No Token, Please log in again'}
I want to know why it does not work and how to debug.
Related
I would like to write an api with django rest framework, I got some issues with my callback function.
I can get the access code, but how to give it to my app?
This is my callback function :
#api_view(['GET'])
def callback(request):
if request.method == 'GET':
code = request.GET.get("code")
encoded_credentials = base64.b64encode(envi.SECRET_ID.encode() + b':' + envi.SECRET_PASS.encode()).decode("utf-8")
token_headers = {
"Authorization": "Basic " + encoded_credentials,
"Content-Type": "application/x-www-form-urlencoded"
}
token_data = {
"grant_type": "authorization_code",
"code": code,
"redirect_uri": "http://127.0.0.1:800/callback"
}
test = "test :" + code
return JsonResponse(test, safe=False)
And this is my view where I try to do some stuff (I use spotify's API, with spotipy), I need to get the users name or mail :
#api_view(['GET'])
#permission_classes([permissions.IsAuthenticated])
def test(request):
if request.method == 'GET':
test = "test " + request.user.username
scope = "user-read-private"
sp = getScope(scope)
print(sp.current_user())
urn = 'spotify:artist:3jOstUTkEu2JkjvRdBA5Gu'
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id=envi.SECRET_ID, client_secret=envi.SECRET_PASS, redirect_uri=envi.SPOTIPY_REDIRECT_URI))
artist = sp.artist(urn)
print(artist)
user = sp.current_user()
return JsonResponse(user, safe=False)
def getScope(spotipyScope):
token = SpotifyOAuth(scope=spotipyScope,client_id=envi.SECRET_ID, client_secret=envi.SECRET_PASS, redirect_uri=envi.SPOTIPY_REDIRECT_URI)
spotifyObject = spotipy.Spotify(auth_manager= token)
return spotifyObject
When I do a get on 127.0.0.1:8000/test/, I have a new page on my browser, from spotify, I connect my account, and then, it redirects me on 127.0.0.1:8000/callback/?code=some_code
How can I give it to my first page waiting for the code so I can print the users stuff pls?
I am working with Postman for the first time and GET request to my simple API is working fine, but when I try POST request it gives me an error and I have no idea where is the problem. Can you please advise?
API function:
#app.route('/customer', methods=['POST'])
def create_customer():
request_data = request.get_json()
new_customer = {
"email": request_data['email'],
"username": request_data['username'],
"name": request_data['name'],
"newsletter_status": request_data['newsletter_status'],
"trips": []
}
for customer in customers:
if customer['username'] == new_customer['username']:
return jsonify({'error': 'username already exist'})
customers.append(new_customer)
return jsonify(new_customer)
Screenshots from postman
This I put in the body + error message
Headers set up - Content-Type application/json
I think your new customer variables should not be in string format, I don't know why they are and also try my option for getting the request body:
import json
def create_customer():
request_data = json.loads(request.body)
new_customer = {
email = request_data['email'],
username = request_data['username'],
name = request_data['name'],
newsletter_status = request_data['newsletter_status'],
trips: []
}
for customer in customers:
if customer['username'] == new_customer['username']:
return jsonify({'error': 'username already exist'})
customers.append(new_customer)
return jsonify(new_customer)
Yur code works fine , i just tested with postman:
from flask import jsonify
from flask import Flask
from flask import request
app = Flask(__name__)
#app.route('/')
def hello_world():
return 'Hello, World!'
#app.route('/customer', methods=['POST'])
def create_customer():
customers=[]
customers.append(request.get_json())
request_data = request.get_json()
new_customer = {
"email": request_data['email'],
"username": request_data['username']+"HHH",
"name": request_data['name'],
"newsletter_status": request_data['newsletter_status'],
"trips": []
}
print(new_customer['username'])
print(customers[0]['username'])
for customer in customers:
if customer['username'] == new_customer['username']:
return jsonify({'error': 'username already exist'})
customers.append(new_customer)
return jsonify(new_customer)
Can you check what is exactly send in postman ?
you can do it by clicking console ( can get from left botom corner or by pressing ctrl+alt+c ) >request > requestbody
I've build a small flask application with a file input form, and now I want that file to be sent to an API.
#app.route('/test', methods=['POST', 'GET'])
def test():
if request.method == 'POST':
file = request.files['file']
file.save(secure_filename(file.filename))
My Layout for the post part:
data = {
"local": file,
"name": file.filename
}
rp = requests.post(f'https://www.meistertask.com/api/tasks/{task_id}/attachments', data, headers={'Authorization': f'Bearer {access_token}'})
print(rp.status_code)
print(rp.content)
No matter how I try to post that file to the API, I always get this response:
{
"errors": [
{
"message": "Parameter local should be of type ActionDispatch::Http::UploadedFile!",
"status": 400
}
]
}
I really don't know how to post a file of that type from my uploaded file in flask.
I'd really appreciate any help! Thank you very much in advance.
file is not a real file, but a filestorage from the werkzeug package.
https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.FileStorage
The API documentation of meistertask is not clear to me, especially I cannot see what local should be. A path? A stream? Bytes?
I got it working with python urlib... maybe this helps you
f = open(fname,'rb')
content = f.read()
f.close()
url = 'https://www.meistertask.com/api/tasks/%s/attachments' % (task_id)
request = urllib.request.Request("%s" %(url))
boundary = "5645645645654"
request.add_header("User-Agent", "python-test")
request.add_header("Accept", "*/*")
request.add_header("Accept-Encoding", "gzip, deflate")
request.add_header("Content-Type","multipart/form-data; boundary=%s" % boundary)
request.add_header("Connection", "keep-alive")
request.add_header("Expect", "100-continue")
request.add_header("Authorization", "Bearer 11111111111111111111")
body = bytes("--%s\r\n" % boundary,'utf-8')
body += bytes('Content-Disposition: form-data; name="name"\r\n\r\n','utf-8')
body += bytes('%s\r\n' % fname,'utf-8')
body += bytes("--%s\r\n" % boundary,'utf-8')
body += bytes('Content-Disposition: file; name="local"; filename="%s"\r\n' % fname,'utf-8')
body += bytes('Content-Type: text/plain\r\n\r\n','utf-8')
body += content
body += bytes('\r\n','utf-8')
body += bytes("\r\n--%s--\r\n" % boundary,'utf-8')
request.data = body
#print(body)
f = urllib.request.urlopen(request)
response = f.read() #bytes
Currently my API requires to use Token authentication.
POST /api/authorize HTTP/1.1
"version": "20151130", // The version of the REST API you are using
"client_id": "01234567890123456789", // Your 20 char public client id
"client_secret": "0123456789..." // Your 40 char client secret
I get the response:
{
"auth_token": "abcdef...",
"auth_expires": "20180524T062442Z"
}
My current pattern is like this:
I have a list of items I need to pass to the API via POST method.
This is my main function: ProcessProducts which receives a Pandas Dataframe which includes a product per row.
def ProcessProducts(products):
all_results = []
for _, product in products.iterrows():
results = GetProductData(product)
if results:
all_results.extend(results)
return all_results
def GetAuthorizationToken():
payload = {
'version': api_version,
'client_id': api_client_id,
'client_secret': api_client_secret
}
request_url = '%s%s' % (api_host, '/api/authorize')
r = requests.post(request_url, data=payload)
if r.status_code != 200:
raise Exception('Failed to authorize: ' + r.text)
token_data = json.loads(r.text)
api_auth_token = token_data['auth_token']
api_auth_expires = token_data['auth_expires']
return {
"X-API-Version": api_version,
"Authorization": "token %s" % api_auth_token
}
Client function...
def GetProductData(self, product):
"""Gets Product information from API."""
url = '%s%s' % (self.api_url, _COMPANY_DATA)
request = json.dumps({'products': [product]})
form_data = {'request': request, 'start': 1, 'limit': 1000}
logging.info('Looking up: %s', url)
auth_headers = GetAuthorizationToken()
response = _SendApiRequest(url, auth_headers, form_data)
return _HandleResponse(response)
def _SendApiRequest(self, url, auth_headers, form_data):
session = requests.Session()
try:
response = session.post(
url,
timeout=(_CONNECT_TIMEOUT_SECONDS, _READ_TIMEOUT_SECONDS),
headers=auth_headers,
data=form_data,
verify=True) # Check for valid public/signed HTTPS certificate.
response.raise_for_status()
return response
except requests.exceptions.HTTPError as err:
logging.exception(err)
Questions:
API returns the code expiry field "auth_expires", Where may be the best way to check in code when token expires so I can request a new one?
Is there a better Pattern to call API, so I can control the QPS rate as well (Use RateLimiter). Right now I'm creating a Session per request, which may not be ideal.
my deorator function...
def validate_captcha(view):
'''Decorator to validate a captcha based on settings'''
def failure():
return HttpResponse('You need to complete the captcha, please refresh and try again')
if request.method == 'POST':
url = "https://www.google.com/recaptcha/api/siteverify"
values = {
'secret': settings.GOOGLE_RECAPTCHA_SECRET_KEY,
'response': request.POST.get(u'g-recaptcha-response', None),
'remoteip': request.META.get("REMOTE_ADDR", None),
}
data = urllib.urlencode(values)
req = urllib2.Request(url, data)
response = urllib2.urlopen(req)
result = json.loads(response.read())
# result["success"] will be True on a success
if result["success"]:
return view
else:
return fail
return fail
and then my view...
#validate_captcha
def sendemail(request):
...
I could put the request in the decorator args, but then it is undefined when i put it in the view args. I tried calling it a few others ways without success, how would you put it in there?
You need to have a wrapper function:
def validate_captcha(view):
def wrap(request, *args, **kwargs):
if request.method == 'POST':
url = "https://www.google.com/recaptcha/api/siteverify"
values = {
'secret': settings.GOOGLE_RECAPTCHA_SECRET_KEY,
'response': request.POST.get(u'g-recaptcha-response', None),
'remoteip': request.META.get("REMOTE_ADDR", None),
}
data = urllib.urlencode(values)
req = urllib2.Request(url, data)
response = urllib2.urlopen(req)
result = json.loads(response.read())
# result["success"] will be True on a success
if result["success"]:
return view
else:
return fail
return fail
return wrap
Make sure study this awesome and quite detailed overview on decorators in Python (I personally think, it is one of the best SO answers ever):
https://stackoverflow.com/a/1594484/771848