How do I make independent API's? - python

I'm far from being an expert on the topic and my question might even make no sense, but I'm trying to make an app that gathers data from a server I made. There's a Python script I made that logs into a website and scrapes data from it. When you make a GET request to the API, the Python functions get called and the data is put on a server for the app to take. Thing is: whenever a user makes a GET request (or even a POST request, to send the credentials needed for the Python script to log in), the server changes for every user. For example, if a user posts his credentials, the dictionary "credentials" is changed for everyone and if a second user posts his credentials at the same time, the dictionary might get the wrong values for one of the two users. Here's the code:
from flask import Flask, request, jsonify
import backend as b
app = Flask(__name__)
credentials = dict()
subjectNames = ['Italiano', 'Inglese', 'Filosofia', 'Storia', 'Matematica', 'Informatica', 'Fisica', 'Scienze', 'Arte', 'Educazione Fisica']
#app.route('/login', methods=['POST'])
def getCredentials():
if request.method == 'POST':
username = request.get_json(force=True).get('username')
password = request.get_json(force=True).get('password')
credentials['username'] = username
credentials['password'] = password
return jsonify({'credentials': credentials})
#app.route ('/creds', methods=['GET'])
def creds():
return jsonify({'credentials': credentials})
#app.route('/api', methods=['GET'])
def api():
if request.method == 'GET':
query = str(request.args['query'])
if query == 'marks':
d = {}
m = b.getFullMarks(b.login(credentials['username'], credentials['password']))
for i in range(len(subjectNames)):
d[subjectNames[i]] = m[i]
return jsonify(d)
elif query == 'names':
d = {}
m = b.getNames(b.login(credentials['username'], credentials['password']))
for i in range(len(subjectNames)):
d[subjectNames[i]] = m[i]
return jsonify(d)
elif query == 'calendar':
d = {}
m = b.calendar(b.login(credentials['username'], credentials['password']))
d['Calendar'] = m
return jsonify(d)
elif query == 'badge':
d = {}
m = b.badge(b.login(credentials['username'], credentials['password']))
d['Badge'] = m
return jsonify(d)
if __name__ == '__main__':
app.run()

Leaving aside the fact that you keep all of the credentials in memory, and if the server crashes, you lost everything.
You can't use a dictionary to do as you want, as you already know, a dictionary can only hold a single representation of the same key (in our case, 'username'). so when a 2nd user calls the /login endpoint, you're overwriting the previous one and vice versa.
As mentioned before, most applications will generate a token on a successful login, and will send it back to the calling user.
The user will add it as a header on his upcoming requests, this allows the service to identify the calling user, and do whatever it needs.
You can look for existing implementations, or do something on your own.
but eventually, you'll need to map the token to the user, e.g:
#app.route('/login', methods=['POST'])
def getCredentials():
if request.method == 'POST':
username = request.get_json(force=True).get('username')
password = request.get_json(force=True).get('password')
token = generate_token_for_user(username, password)
credentials[token] = {'username': username, 'password': password}
return jsonify({'token': token})
and in the api call:
#app.route('/api', methods=['GET'])
def api():
token = request.headers['Authorization'] # assuming you're using this for your token
creds = credentials.get(token)
d = {}
if request.method == 'GET':
query = str(request.args['query'])
if query == 'marks':
m = b.getFullMarks(b.login(creds['username'], creds['password']))
for i in range(len(subjectNames)):
d[subjectNames[i]] = m[i]
return jsonify(d)
elif query == 'names':
m = b.getNames(b.login(creds['username'], creds['password']))
for i in range(len(subjectNames)):
d[subjectNames[i]] = m[i]
return jsonify(d)
elif query == 'calendar':
m = b.calendar(b.login(creds['username'], creds['password']))
d['Calendar'] = m
return jsonify(d)
elif query == 'badge':
m = b.badge(b.login(creds['username'], creds['password']))
d['Badge'] = m
return jsonify(d)
Offcourse, that maintaining a token lifecycle is a bit more complex, need to invalidate the token after a period of time, and you'll need to validate it on every request (usually with a middleware), but this is the concept.

Related

Flask: Bad Request POST 400

I use flask and firebase. I have 2 button in satis.html . When user press button2 , i want to retrieve some data from database and show it. But i get " Bad Request " Error.
Heres my code :
#app.route('/satis', methods=['GET', 'POST'])
def satis():
if (request.method == 'POST'):
sehir=request.form['il']
yas=request.form['yas']
id=request.form['id']
gun=request.form['satisgunu']
cins=request.form['cinsiyet']
tarz=request.form['satistarzi']
db = firebase.database()
db.child("names").push({"sehir": sehir,"yas":yas,"id":id,"gun":gun,"cins":cins,"tarz":tarz})
todo = db.child("names").get()
to = todo.val()
if request.form['submit'] == 'add':
db = firebase.database()
users_by_score = db.child("names").order_by_child("id").equal_to("2").get()
us = users_by_score.val()
return render_template('satis.html', t=to.values(),u=us.values())
return render_template('satis.html', t=to.values())
You have only handled for post method. You need to also handle the GET method situation.
#app.route('/satis', methods=['GET', 'POST'])
def satis():
db = firebase.database()
todo = db.child("names").get()
to = todo.val()
if (request.method == 'POST'):
sehir=request.form['il']
yas=request.form['yas']
id=request.form['id']
gun=request.form['satisgunu']
cins=request.form['cinsiyet']
tarz=request.form['satistarzi']
db.child("names").push({"sehir": sehir,"yas":yas,"id":id,"gun":gun,"cins":cins,"tarz":tarz})
if request.form['submit'] == 'add':
db = firebase.database()
users_by_score = db.child("names").order_by_child("id").equal_to("2").get()
us = users_by_score.val()
return render_template('satis.html', t=to.values(),u=us.values())
return render_template('satis.html', t=to.values())

How to set a request's limit to a joken JWT

I'm working in an API with python, flask and implementing JWT with a timeout for expiration, but I'd like to set also a limit request, So the token is gonna be invalid if the time is out or the token has been used in five requests.
I'd been working with the timeout for expiration, but I can't find how to implement the expiration by five requests. Thanks by the help.
The Code til now:
from flask import *
import jwt
import datetime
from flask_pymongo import PyMongo
from functools import wraps
import hashlib
app = Flask(__name__)
app.config['MONGO_DBNAME'] = 'MONGOCONEX'
app.config['MONGO_URI'] = 'mongodb://localhost:27017/MONGOCONEX'
app.config['log_log_1'] = 'LOGKEYCONNECT'
app.config['key1'] = 'SECRECTKEY'
app.config['key2'] = 'PASSKEY'
mongo = PyMongo(app)
def token_required(f):
#wraps(f)
def decorated(*args, **kwargs):
token = request.args.get('token')
if not token:
return jsonify({'error': 402,'message':'Token is missing'})
try:
data = jwt.decode(token, app.config['key1'])
except:
return jsonify({'error': 403,'message': 'Token Invalid'})
return f(*args, **kwargs)
return decorated
#app.route('/results', methods=['GET'])
#token_required
def get_all_stars():
results = mongo.db.resultados
output = []
date_start = datetime.datetime.now() - datetime.timedelta(days=1*365)
date_end = datetime.datetime.now() + datetime.timedelta(days=1*365)
for s in results.find():
#print(s)
if date_start <= s['day'] <= date_end:
output.append({'day':s['day'], 'monthly_prediction':s['monthly_prediction'], 'percent_prediction':s['percent_prediction']})
return jsonify({'result' : output})
#app.route('/login', methods=['GET'])
def login():
log_key = request.args.get('l_k')
password_k = request.args.get('p_k')
md5_hash = hashlib.md5()
md5_hash.update(b""+app.config['key2']+"")
encoded_pass_key = md5_hash.hexdigest()
if (log_key == app.config['log_log_1']) and (password_k == encoded_pass_key):
token = jwt.encode({'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=2)}, app.config['key1'])
return jsonify({'token': token.decode('UTF-8')})
return jsonify({'error': 401, 'description': 'Not verified', 'Wrong Auth': 'Auth Required'})
if __name__ == '__main__':
try:
app.run(debug=True)
except Exception as e:
print('Error: '+str(e))
I see you're using mongo, the workflow is you can put counter along with the token in mongo database and count it how many it has been used, then adding logic to compare which one comes first, the time limit or how many times the token has been used, if it has been used five times you can revoke the token & generate a new token or another workflow you want to do. Here's the further reference to revoke/blacklist the token after it has been accesed five times https://flask-jwt-extended.readthedocs.io/en/stable/blacklist_and_token_revoking/

request.POST.get() returning none

I am running a website using Django. I am trying to Login but it is returning none and i am not getting any error. It shows 200 status code.
Here is my views.py code:
def user_login(request):
datas= {'log':False}
if request.method == "POST":
usern=request.POST.get('Username')
passw=request.POST.get('password')
response = requests.post(url='http://www.onebookingsystem.com/productionApi/API/Admin/login.php',data={"Username":usern,"password":passw})
json_data = response.json()
if json_data['status'] == 1:
user=authenticate(Username=usern,password=passw)
login(request,user)
range_yearly = 0
range_monthly = 0
respo = requests.get(url='http://www.onebookingsystem.com/productionApi/API/Admin/admin_dashboard.php')
data_dash = json.loads(respo.text)
when i am running in POST HTTP request,it shows successfully logged in,but
in GET HTTP request, it shows :Status 0 "mobile or password is missing".//required post params is missing.
This is propably because you're using requests without the session storage.
You can try it this (untested) way:
def user_login(request):
# Create client with session storage to store session cookies
client = requests.Session()
datas= {'log':False}
if request.method == "POST":
usern=request.POST.get('Username')
passw=request.POST.get('password')
# client stores session cookie at login
response = client.post(url='http://www.onebookingsystem.com/productionApi/API/Admin/login.php',data={"Username":usern,"password":passw})
# you can check that with
# print(client.cookies)
json_data = response.json()
if json_data['status'] == 1:
user=authenticate(Username=usern,password=passw)
login(request,user)
range_yearly = 0
range_monthly = 0
# client should be able to access because of its stored session cookie
respo = client.get(url='http://www.onebookingsystem.com/productionApi/API/Admin/admin_dashboard.php')
data_dash = json.loads(respo.text)
More information

Redirect url clashes with flask-;login

I currently have a flask server and an angular js front end on which users can buy things from third party vendors.
These third party vendors have their own payment gateways to which I connect my front end to... So at the point of making the payment, we redirect the user to the payment gateway... Once a payment is made, we have a redirect url on our flask servers that captures the success message (and the payment details).
The issue here is that since we do it on the front end (and since this is a third party's website), the flask-login does not seem to work. We use session to store some of the data of the purchase and thus, we cant seem to be able to connect the product the customer has bought with the transaction he made to buy it!
I have given my apis below:
#api.route('/quoteRequest/',methods = ['POST'])
# #flask_login.login_required
def carquote():
data = request.get_json()
c = quoteController.FUTGENGI(data = data, lob = "Motor", stage="quote")
d = c.finOutput
finalQuotes = []
finalQuotes.append(d)
return Response(json.dumps(finalQuotes),mimetype = "application/json")
#api.route("/proposalRequest/",methods = ['POST'])
def proposalRequest():
data = request.get_json()
current_app.logger.debug(data)
c = quoteController.FUTGENGI(data = data, lob = "Motor", stage="proposal")
output = json.loads(c.quoteDict)
session['proposal'][data['Quote']['insurerID']] = data
return Response(json.dumps(output),mimetype = "application/json")
#Redirect URL:
#api.route('/FUTGENGI/policyCreate/', methods = ['GET','POST'])
def policyCreate(insurerID):
if request.method == "GET":
par = OrderedDict(
WS_P_ID = request.args.get('TranID')
TID = request.args.get('UID')
PGID = request.args.get('PaymentID')
Premium = request.args.get('Amt')
Response = request.args.get('Response')
)
if(par['Response'] == "Success"):
for k,v in par.items():
session['proposal']['FUTGENGI'][k] = v
c = quoteController.FUTGENGI(data = session['proposal']['FUTGENGI'], lob = "Motor", stage="payment")
return Response(json.dumps(c.paymentOutput), mimetype = "application/json")
else:
return Response(json.dumps({"output":"Oops. Something went wrong. Please try again"}), mimetype = "application/json")

Django Responds code 500 no matter what

I have a method in Django where I get POST data from a mobile app and all I do is save it and send a Response. The problem is though the the data gets saved but no matter what the app receives the response code 500.
<Response [500]>
code:
#csrf_exempt
def store_recordings(request):
if request.method == 'POST':
print "In POST",request.POST
driverName = request.POST['driverName']
driverMobileNum = request.POST['driverMobileNum']
customerMobileNum = request.POST['customerMobileNum']
salesOrderNo = request.POST['salesOrderNo']
callRecord = request.POST['callRecord']
latitude = request.POST['latitude']
longitude = request.POST['longitude']
callStart = request.POST['callStart']
callEnd = request.POST['callEnd']
callDuration = request.POST['callDuration']
callType = request.POST['callType']
driverrecording = DriverRecording(driverName=driverName,driverMobileNum=driverMobileNum,customerMobileNum=customerMobileNum,salesOrderNo=salesOrderNo,callRecord=callRecord,latitude=latitude,longitude=longitude,callStart=callStart,callEnd=callEnd,callDuration=callDuration,callType=callType)
save_or_not = driverrecording.save()
driverexist = DriverNames.objects.all()
new_driver_flag = False
driverName_list = [each.driverName for each in driverexist]
driverName_list = list(set(driverName_list))
if driverName in driverName_list:
pass
else:
DriverNames(driverName=driverName,driverMobileNum=driverMobileNum).save()
return HttpResponse(status=201)
else:
return HttpResponse(status=400)
I am perplexed what is the problem.
Thanks.
Almost certainly, one or more of those fields is not being sent, so you are getting a KeyError. If you set DEBUG to True you would see the traceback.
You should be using Django's forms framework, instead of directly accessing the POST data. That will validate the input and allow you to display any errors.

Categories