Flask show return data on request - python

I have some problems.
I am new to python and flask.
I am building an API that makes queries to a database, a separate application front end and back end. But problems have come to rescue the search result with the Flask.
Example:
The Following 'curl' command registers a new user with username 'miguel' and password 'python':
$ Curl -X POST -H -i "Content-Type: application / json
'd' {"username":" miguel","password":"python"} 'http://127.0.0.1:5000/api/users
RETURN:
HTTP / 1.0 201 CREATED Content-Type: application / json
Content-Length: 27 Location: http://127.0.0.1:5000/api/users/1 Server:
Werkzeug / Python 0.9.4 / 2.7.3 Date: Thu, 28 Nov 2013 19:56:39 GMT {
"username": "miguel" }
Through doterminal we return the username, someone knows a way to retrieve and display the user's name on the front end.
Resaltar it should consider font end and back and running on different machines.
--------UPDATE-------
BACKEND
#app.route('/api/users', methods=['POST'])
def new_user():
username = request.json.get('username')
password = request.json.get('password')
if username is None or password is None:
abort(400) # missing arguments
if User.query.filter_by(username=username).first() is not None:
abort(400) # existing user
user = User(username=username)
user.hash_password(password)
db.session.add(user)
db.session.commit()
return (jsonify({'username': user.username}), 201,
{'Location': url_for('get_user', id=user.id, _external=True)})
FRONTEND
#home_blueprint.route('/cadastro', methods=['POST'])
def cadastro():
username = request.form['username']
password = request.form['password']
if username and password:
url = 'http://127.0.0.1:4000/api/users'
payload = {'username': username,'password':password}
headers = {'content-type': 'application/json'}
r = requests.post(url, data=json.dumps(payload), headers=headers)
else:
return "ERRO"
return "Create new user sucesso!"

(post my comment as an answer)
You could simply use r.text to get the requests.post's retun data, from the document:
When you make a request, Requests makes educated guesses about the encoding of the response based on the HTTP headers. The text encoding guessed by Requests is used when you access r.text.
So just replace
return "Create new user sucesso!"
with
return r.text
In this case, r.text is requests.post(url, data=json.dumps(payload), headers=headers) return data, was created by:
return (jsonify({'username': user.username}), 201,
{'Location': url_for('get_user', id=user.id, _external=True)})

Related

Not able to get values stored in Python Django request session

Hellos firends,
I have REST service in Python Django application. I am trying to store some values in the request session post successful login service call.
like the following
request.session['valid']=True
and the I am able to check that the values set properly.
The in the next request when I am trying to retrieve the value I am not able to find any of the keys I had stored.
following is the code to retrieve the keys
if 'valid' not in request.session:
print('Invalid request. . .')
return False
elif request.session['valid']==True:
username=request.session['username']
print('Request validated. . .')
return True
I have the frontend app running on React and Backend REST is on DRF. After the login is done on the following code,
#csrf_exempt
#api_view(['POST'])
def login_details(request):
if request.method == 'POST':
headers = {
'Content-type': 'application/json',
}
# Assuming at this point login is successful, so I am setting the session
request.session['username']=TF_VAR_user_name
request=initSession(request)
data = txt
response = requests.post('https://hooks.slack.com/services/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', headers=headers, data=data)
print(response)
return Response(data_json)
except cx_Oracle.DatabaseError as exc:
error, = exc.args
m = error.message
err="Oracle-Error-Message: "+ str(error.code) + " Oracle-Error-Message: "+error.message
dic2={"Oracle-Error-Code":str(error.code),"Oracle-Error-Message":error.message}
print(dic2)
m=json.dumps(dic2)
n=json.loads(m)
txt="{'text':'User "+atp_userid+" Oracle-Error-Message: "+error.message+"'}"
data = txt
response = requests.post('https://hooks.slack.com/services/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', headers=headers, data=data)
return Response(n)
else:
return Response({ "message":"Unauthoried, please login."},status=status.HTTP_401_UNAUTHORIZED)
The I am trying to read Stored values in the following code,
#csrf_exempt
#api_view(['POST'])
def dashboard(request):
if 'valid' not in request.session:
print('Invalid request. . .')
elif request.session['valid']==True:
username=request.session['username']
print('Request validated. . .')
Please help me how can store values in session and retrieve in the subsequent request. I am sorry for the trouble as I am completely new to Python and Django

API end point testing using behave

I have a django rest API end point login which takes username and password in form of json object as below.
{
username: email,
password: password,
}
and returns a json object containing a token
{
token : 0234jh324234j2hiy342
}
Now i want to write a test in behave. I have following feature file.
Feature: Login User
By providing different credentials we check if our login API end point is working as expected or not
Scenario: Login User by Providing Authentication Credentials
Given I provide user authentication credentials
Then I must get a reponse with status code 200 and a jSon object with token
and following is my auth.py file
from behave import *
import requests
import json
#given('I have user authentication credentials')
def set_impl(context):
url = 'https://example.com/v1/login'
headers = {'content-type': 'application/json'}
body = {
"username": "xyz#email.com",
"password": "abcdef123",
}
#when('I make an http post call')
def step_impl(context):
context.res = requests.post(url, data=json.dumps(body), headers=headers)
#then('I must get a reponse with status code 200 and a jSon object with token')
def step_impl(context):
assert context.res.status == 200
I am unable to access the url, header and body from #given decorator in #when decorator. And how can i check the json in response against my expected json.
Per #KlausD.'s suggestion, you should add your variables to the behave's context object. I've edited your code to add your variables as the context object's attributes.
from behave import *
import requests
import json
#given('I have user authentication credentials')
def set_impl(context):
context.url = 'https://example.com/v1/login'
context.headers = {'content-type': 'application/json'}
context.body = {
"username": "xyz#email.com",
"password": "abcdef123",
}
#when('I make an http post call')
def step_impl(context):
context.res = requests.post(context.url, data=json.dumps(context.body), headers=context.headers)
#then('I must get a reponse with status code 200 and a jSon object with token')
def step_impl(context):
assert context.res.status == 200
As for checking the JSON in your response against your expected JSON...
Check out the requests package's response object here to find out how to get the response object's attributes.
Open your own expected JSON file via open(), grab the value that corresponds to the token key, and do an assert expectedToken == responseToken, or something of that sort.

flask: When unittesting, request.authorization is always None

I hope that somebody can help me.
I have to write a unit test with unittest of Python in a flask api. I have a login route that works perfectly fine when accessing it through the app with a React frontend but whenever I tried to post from the test, the request.authorization is None... It drives me crazy
I looked all over the internet and tried a lot of different approach but whatever I do, request.authorization is always None when doing a test
Testing :
import unittest
import base64
from backend.peace_api import app
class TestLogin(unittest.TestCase):
# Assert login() with correct authentication
def test_login(self):
with app.app_context():
tester = app.test_client(self)
auth = 'seo#hotmail.com:password'
authheader = base64.b64encode(bytes(auth, 'UTF-8'))
headers = {"HTTP_AUTHORIZATION": "Bearer " + str(authheader), "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"}
response = tester.post('/api/login/', headers=dict(headers))
print(response.json)
self.assertEqual(response.status_code, 200)
if __name__ == '__main__':
unittest.main()
Route :
import jwt
import datetime
from flask import Blueprint, request, jsonify
from backend.peace_api import database, secret_key
from backend.peace_api.flat.models.flat import Flat
login_blueprint = Blueprint("login", __name__)
#login_blueprint.route("/", methods=["POST"])
def login():
auth = request.authorization # This here is always None
print("Hello World")
print(request)
print(request.authorization)
if auth is None:
return jsonify({"success": False}, 401)
email = auth.username
password = auth.password
if email is None or email is None or password is None:
return jsonify({"success": False}, 500)
mongo_flat = database.flats.find_one({"email": email})
if mongo_flat is not None:
flat = Flat(
mongo_flat["_id"],
mongo_flat["name"],
mongo_flat["email"],
mongo_flat["password"],
mongo_flat["tasks"],
mongo_flat["members"],
)
if password == flat.password and email == flat.email:
token = jwt.encode(
{
"id": str(flat.id),
"exp": datetime.datetime.utcnow() + datetime.timedelta(minutes=30),
},
secret_key,
)
return jsonify({"token": token.decode("UTF-8")})
else:
return jsonify({"success": False}, 401)
else:
return jsonify({"success": False}, 401)
Printed message :
Testing started at 19:15 ...
Launching unittests with arguments python -m unittest test_login.TestLogin in [...]\tests
Hello World
<Request 'http://localhost/api/login/' [POST]>
None
Ran 1 test in 0.017s
OK
[{'success': False}, 401]
I have honestly no clue what I should do... Thanks for the help
So there are a few issues with your setup which are resulting in the header not being sent or being sent but being malformed.
The name of the header is "Authorization", not "HTTP_AUTHORIZATION".
The credentials value for the Authorization header needs to be base64 encoded per the spec.
The default authorization middleware for Werkzeug only supports Basic auth, so your Bearer token will not work unless you're using an extension that adds Bearer support to Werkzeug (without knowing more about your setup it's hard to know what's going on there).
Here's a very simplified Flask App that demonstrates a working test client with a functioning Authorization header:
import flask
import base64
app = flask.Flask("app")
#app.route("/")
def test():
print(flask.request.authorization)
return "Worked"
with app.test_client() as c:
c.get("/", headers={"Authorization": "Basic {}".format(base64.b64encode(b"useo#hotmail.com:pass").decode("utf8"))})
Which prints:
{'password': 'pass', 'username': 'seo#hotmail.com'}
<Response streamed [200 OK]>
A similar question was asked here:
Flask werkzeug request.authorization is none but Authorization headers present

Flask HTTPBasicAuth none token inside header

I'm trying to resolve problem with Basic Authentication in flask using HTTPBasicAuth.
When I'm accessing using curl or web browser everything works well.
This are examples which works:
curl -u [access_token]:unused -i X GET http://127.0.0.1:5000/api/v1/token
or
http://[access_token]:unused#127.0.0.1:5000/api/v1/token
But when I'm using Authorization: Basic [token] or Authorization: Basic [token]:unused in header of request I get 500 error from server.
Verifying access token or email and password:
#auth.verify_password
def verify_password(email_or_token, password):
user = User.verify_auth_token(email_or_token)
if not user:
user = User.query.filter_by(email = email_or_token).first()
if not user or not user.verify_password(password):
return False
g.user = user
return True
User model:
class User(db.Model):
def generate_auth_token(self, expiration = 600):
s = Serializer(app.config['SECRET_KEY'], expires_in = expiration)
return s.dumps({ 'id': self.id })
#staticmethod
def verify_auth_token(token):
s = Serializer(app.config['SECRET_KEY'])
try:
data = s.loads(token)
except SignatureExpired:
return None # valid token, but expired
except BadSignature:
return None # invalid token
user = User.query.get(data['id'])
return user
I found that when I'm using token or email and password in header as Basic [token/email]:[password/unused], email_or_token and password properties are None.
Error: TypeError: argument of type 'NoneType' is not iterable
Why error occurs while using Authorization: Basic [token/email]:[password/unused] in header of request? What is solution for this?
You must Base64-encode the the credential portion of your Authorization header. This can be done with the command line base64 utility.
echo 'token:unused' | base64
From the example here, the username password combination of Aladdin:OpenSesame becomes:
Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l
The reason that you don't have to worry about this with curl or the browser, is that they will perform the encoding automatically for you.

MailChimp bad request JSONParseError with Python

I am trying to hook up to MailChimp's api, in my Django application, to add an email to one of my lists. Seems pretty simple enough. I add my api key to the header of the request, with the email address and other variable in the body of the request. every time I try and connect though, I get a response status code of 400. The message says there is a JSON parsing error, and that my JSON is either formatted incorrectly, or there is missing data required for the request. I am making this same api call however with Postman, and am getting a good response back.
view function
import requests
def join_newsletter(request, email):
# hash the user's email for mailchimp's API
# m = hashlib.md5()
# c_email = email
# m.update(c_email.encode('utf-8'))
# email_hash = m.hexdigest()
api_key = 'apikey ' + settings.MAILCHIMP_API
api_endpoint = api_endpoint
data = {
"email_address": email,
"status": "subscribed"
}
header = {
'Authorization': api_key
}
r = requests.post(api_endpoint, data=data, headers=header)
message = r.content
return message

Categories