Routing URL Requests using Flask - python-2.7

I have been working on implementing PyTeaser as an API so can send requests using my program to get a summary of an article. I have been trying to figure out how to send url requests to the API using flask. I was having trouble routing my url request because I didn't really understand what goes in the ???? under app route section below so that I can route my requests.
from flask import Flask, jsonify
from PyTeaser import SummarizeUrl
from PyTeaser import Summarize
app = Flask(__name__)
#app.route('????', methods=['GET'])
def summary_url(url):
summary = SummarizeUrl(url)
return jsonify({'title': title, 'url': url, 'summaries': summary})
#app.route('????', methods=['GET'])
def summary(title, text):
summary = Summarize(title, text)
return jsonify({'title': title, 'summaries': summary})
if __name__ == '__main__':
app.run(debug=True,app.run(host='0.0.0.0'))

Something like
#app.route('/<url>')
I'm not sure second route as it looks like you want to take in two variables.
But possibly:
#app.route('/<title>/<text>')

Related

CSRF invalid token for API call in Flask

My objective is to build Rest API on Flask. When i send post JSON request to the server from Postman application http://127.0.0.1:5000/api/v1/posts/add/post, I get "The CSRF token is missing" Error.
Respective route is here:
#api.route('/posts/add/post', methods=['POST'])
def add_post():
subject = request.json['subject']
body = request.json['body']
myPost = Post(subject=subject, body=body, category_id=1)
db.session.add(myPost)
db.session.commit()
return post_schema.jsonify(myPost).data
I have looked at different examples and nobody mentions about CSRF for such requests, as usually its used for WTF s.
Can you please advice, what am i doing wrong and fow to fix it?
Based on this extract from the docs, is it possible you are protecting your app like this?
from flask_wtf.csrf import CSRFProtect
csrf = CSRFProtect(app)
Usually, you only need this for basic flask apps (docs):
from flask import Flask
app = Flask(__name__)

How do you get two Flask test clients to communicate using Request

I am new to Flask, and I am trying to learn so I can write pytests for applications I am working on.
In my project, there are two applications that are sometimes communicating; one occasionally sends requests to the other using the 'request' library, and the other sends a response back.
In most of the examples of Flask testing I have seen, it is done by using an application's 'test_client' method. The question I have is on how to get two of these test clients to communicate.
For a toy example, here I have two apps:
flask_app1.py
from flask import Flask
import requests
def create_app():
app = Flask(__name__)
#app.route('/send_message/<msg>')
def send_message(msg):
response = requests.post('http://127.0.0.1:5001/receive_msg', json={'message': msg})
print(response.text)
return "sent:" + response.json()['received']
return app
if __name__ == '__main__':
app = create_app()
app.run()
flask_app2.py
from flask import Flask, request
def create_app():
app = Flask(__name__)
#app.route('/receive_msg', methods=["POST"])
def receive():
msg = request.get_json()["message"]
print(msg)
return {'received': msg}
return app
if __name__ == '__main__':
app = create_app()
app.run(port=5001)
Simply, the first app sends a message to the second, which then sends it back to the first.
Now suppose I have the tests:
import flask_app1
import flask_app2
def test_two_clients():
app1 = flask_app1.create_app()
client1 = app1.test_client()
app2 = flask_app2.create_app()
client2 = app2.test_client()
r = client1.get('/send_message/hello_there')
assert r.status_code == 200
def test_one_client():
app1 = flask_app1.create_app()
client1 = app1.test_client()
r = client1.get('/send_message/hello_there')
assert r.status_code == 200
The bottom test works when flask_app2 is running in a terminal, but that's not what I want.
I am not sure how to get client1 to communicate with client2
I am not aware of any pattern to test two Flask applications against each other, without at least running one.
I acknowledge you do not want to run them, but for completeness:
You could spin up some Docker containers, run your applications there, and test them this way. IMHO this makes perfect sense for an end to end test.
As you do not want to do this, you should think about the implementation of your code. There is pattern called Dependency Injection - this enables you to test your applications completely self contained.
There is an excellent blog post about this https://www.cosmicpython.com/blog/2020-01-25-testing_external_api_calls.html
Other possibilities are to mock the call to the other Flask app or to record its output via https://github.com/kevin1024/vcrpy
I know, this was not the expected answer, but I hope you find something useful.

Authlib - passing authorize url as json

I'm building a SPA using Flask as an api and Vue js as front end. I'm using Authlib for user authentication and planning to use Facebook OAuth. I've already tried the example with Facebook and it's working. But I want to build this in a RESTful way. What I'm trying to do is change this part from app.py from the example:
#app.route('/login')
def login():
redirect_uri = url_for('auth', _external=True)
return oauth.google.authorize_redirect(redirect_uri)
to a json.
Is there a method in the library to get the url of Facebook dialog so that I can pass that as json and do the redirection in Vue?
Do you mean that you want to return a url value in the JSON response?
resp = oauth.google.authorize_redirect(redirect_uri)
url = resp.location
return jsonify(url=url)
Like the above code?
Per the documentation:
>>> import requests_oauthlib
>>> from requests_oauthlib import OAuth2Session
>>> from requests_oauthlib.compliance_fixes import facebook_compliance_fix
>>> facebook = OAuth2Session(client_id='test', redirect_uri='https://test.me')
>>> facebook = facebook_compliance_fix(facebook)
>>> authorization_url, state = facebook.authorization_url('https://www.facebook.com/dialog/oauth')
>>> authorization_url
'https://www.facebook.com/dialog/oauth?response_type=code&client_id=test&redirect_uri=https%3A%2F%2Ftest.me&state=bfipsir5GsKc1CbdPZCgBT0jIn2eq6'

Flask Blueprint : how to run each apps in different port?

I got a flask application with different apps inside, using BluePrint.
To simplify, I got an API that manages token web authentification (and a lot of other data functions) and a website that should call the API to get the valid token, using a basic auth to start with
The issue is that when the website requests the API, it never gets any feedback from the API.
Requesting the API via POSTMAN works like a charm, but this call below, done from a website route is waiting, waiting, waiting and never ends.
So my assumption is that using the same port for both website and api is the issue
I could of course divides the flask into 2 flask apps with 2 servers, but there are many objects and tools both API and website are sharing, so I dont want to double the job
Thanks.
call from the website
from requests.auth import HTTPBasicAuth
import requests
mod = Blueprint('site', __name__, template_folder='templates/login')
def load_user(username, password):
data = requests.get('http://127.0.0.1:5000/api/login',
auth=HTTPBasicAuth('username', 'password'))
return data
#mod.route('/')
def index():
username = 'jeje'
password = 'jeje'
data = load_user(username, password)
return '<h1>load user<h1>'
the api function
#mod.route('/login')
def login():
resu = True
auth = request.authorization
if not auth or not auth.username or not auth.password:
resu = False
user = USER.query.filter_by(username = auth.username).first()
if not user:
resu = False
if validehash(user.password, auth.password):
period_in_mn = 120
payload = {
'public_id':user.public_id,
'exp' : datetime.datetime.utcnow() + datetime.timedelta(minutes = period_in_mn)
}
token = createtoken(payload, current_app.config['SECRET_KEY'])
if resu:
return jsonify({'token' : token })
else:
return jsonify({'token' : 'unknown'})
I guess your using flask 0.12 instead of 1.0. So whats happening here is that you're requesting a route from within another route.
Your browser requests /, and in your index function, you request /login. But the flask process is still working on the / request from the browser, and can't take any other requests, because flask 0.12 is working on a single core only.
Requesting like this is bad design. You could make a helper function, which returns the same data in different requests (either api or main site), or you could make the browser send another request using AJAX.
Flask 1.0 has multicore support, so I think this might work over there, but I really think you should change your design. This has absolutely nothing to do with blueprints by the way.
from flask import Flask, redirect
import requests
app = Flask(__name__)
#app.route('/')
def index():
result = requests.get('http://127.0.0.1:5000/api/login')
return 'this is the index<br>' + result.text
#app.route('/api/login')
def login():
return 'you are logged in'
Using flask 0.12, times out when visiting http://127.0.0.1:5000/.
Using flask 1.0, returns this is the index
you are logged in when visiting http://127.0.0.1:5000/.

Flask-appbuilder RESTful API vs Flask-RESTful API

I am trying to use Flask-appbuilder in an IoT project. So, FAB is used for rapid application buildup and we need dedicated RESTful API for Mobile App and 3rd party service suppliers.
In FAB, there is an implementation for RESTful API, as subclass of BaseCURDView. Most URL is defined as
http://host//api/list
If the mobile app acts as an user agent like browser, it collect username/password, login and access FAB's RESTful API, then permissions, url is not a big deal, everything can follow B/S programming. AKA, all security model is based upon cookie and session. Most of the request information are inside the flask.g.user/flask.request.*.
If the webapp has to support more standard style RESTful API, as described in flask books by miguel. The external webapp has to embed the api key/secret to specified url to exchange token, then use token in header or http parameters to access resources for CRUD operations.
http://host/api/v1/get_token
header:api_key:balabalabala
header:api_secret:abcdefxyz
return {'token':'1234567890'}
http://host/api/v1/resource
header:token:1234567890
return {'resource':'abcdefghijk'}
I have successfully merged them together in FAB's views.py.
from flask import render_template
from flask_appbuilder.models.sqla.interface import SQLAInterface
from flask_appbuilder import ModelView, BaseView, expose
from app import appbuilder, db
from flask import Flask, jsonify
from flask import abort
from flask import make_response
from flask import request
from flask import url_for
tasks = [
{
'id': 1,
'title': u'Buy groceries',
'description': u'Milk, Cheese, Pizza, Fruit, Tylenol',
'done': False
},
{
'id': 2,
'title': u'Learn Python',
'description': u'Need to find a good python tutorial',
'done': False
}
]
def make_public_task(task):
new_task = {}
for field in task:
if field == 'id':
new_task['uri'] = url_for('get_task', task_id=task['id'], _external=True)
else:
new_task[field] = task[field]
return new_task
class ApiView(BaseView):
route_base = "/api/v1"
default_view = "index"
#expose("/index")
def index(self):
#return jsonify({'tasks': map(make_public_task, tasks)})
print repr(request.args)
print repr(request.method)
print repr(request.headers)
return jsonify(tasks)
#expose("/get_token")
def get_token(self):
print repr(request.headers)
return jsonify({'res': True})
#expose("/get_resource")
def get_resource(self):
return jsonify({'res': False})
#expose("/del_resource")
def del_resource(self):
return jsonify({'res': False})
"""
Application wide 404 error handler
"""
#appbuilder.app.errorhandler(404)
def page_not_found(e):
return render_template('404.html', base_template=appbuilder.base_template, appbuilder=appbuilder), 404
db.create_all()
appbuilder.add_view_no_menu(ApiView())
Yes, I can implement standard RESTful API just I did in another flask project with http headers and custom queries with sqlalchemy. But I am not sure if it is the proper way to do that. Since most of the data are requested directly from sqlalchemy raw queries, they are quite different programming experiences.
Open for any suggestions, before moving forward.
Actually FAB's REST API is designed for AJAX, so for mobile app and 3rd party applications, we need a seperate RESTful API, which can follow flask megatutorial and best practice and resue REST-auth library from Miguel.
FAB can work with both anyway.