Can I use Flask Restful alongside an existing Flask App? - python

I have been tasked with working on an existing Flask project (Flask with Templates/Jinja2 style monolith application). I have to add new features to this app and I'm also intending to re-design the app so it becomes a more micro-services based architecure (i.e. initially Flask-restful based backend with React based front-end). Can I just use Flask-restful by just wrapping the existing app and start creating the new endpoints using Resource?
from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
Are there any specific caveats/gotcha's I need to worry about?

Let's try it and see what happens. We start with a basic Flask app:
from flask import Flask
app = Flask(__name__)
#app.route("/")
def index():
return "This is index\n"
#app.route("/endpoint1")
def endpoint1():
return "This is endpoint1\n"
This works and we can request the / and /endpoint1 endpoints and get the expected response:
$ curl localhost:5000
This is index
$ curl localhost:5000/endpoint1
This is endpoint1
Let's see if we can mash a flask_restful managed endpoint in there without disrupting the existing functionality:
from flask import Flask, make_response
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class Widgets(Resource):
def get(self):
return make_response('Yes we have no widgets today\n')
api.add_resource(Widgets, '/widgets')
#app.route("/")
def index():
return "This is index\n"
#app.route("/endpoint1")
def endpoint1():
return "This is endpoint1\n"
Are our original routes still active?
$ curl localhost:5000
This is index
$ curl localhost:5000/endpoint1
This is endpoint1
How about the new one?
$ curl localhost:5000/widgets
Yes we have no widgets today
It looks like the answer is "yes"!

Related

What is the benefit of using Blueprint in Flask-Restful?

I'm new to Flask and the Blueprint concept. I understand the benefit of using Blueprint in a normal Flask application. However, after reading many posts/blogs/documentation, the benefit of using Blueprint with Flask-Restful is still unclear to me.
Let's consider two examples from the Flask-Restful documentation. The first one:
from flask import Flask
from flask_restful import Api
from myapi.resources.foo import Foo
from myapi.resources.bar import Bar
from myapi.resources.baz import Baz
app = Flask(__name__)
api = Api(app)
api.add_resource(Foo, '/Foo', '/Foo/<string:id>')
api.add_resource(Bar, '/Bar', '/Bar/<string:id>')
api.add_resource(Baz, '/Baz', '/Baz/<string:id>')
We have 3 resources. We register them and start the project. Everything is clear at this point. I would be happy with this approach.
Then, they use blueprint:
from flask import Flask, Blueprint
from flask_restful import Api, Resource, url_for
app = Flask(__name__)
api_bp = Blueprint('api', __name__)
api = Api(api_bp)
class TodoItem(Resource):
def get(self, id):
return {'task': 'Say "Hello, World!"'}
api.add_resource(TodoItem, '/todos/<int:id>')
app.register_blueprint(api_bp)
As far as I can see, the code is getting more complicated:
More steps required: create the API instance with the blueprint, register the blueprint with the app,...
If I have another resource, e.g. user, I have to repeat all of those steps (please correct me if I'm wrong):
user_bp = Blueprint('user', __name__)
user_api = Api(user_bp)
user_api.add_resource(User, '/user/<int:id>')
app.register_blueprint(user_bp)
So, what is the benefit of using Blueprint here?
A blueprint in Flask is an object to structure a Flask application into subsets. This helps in organizing code and separating functionality.
For Flask-RESTful this can be used to create an application subset for your api. So for example you have a core blueprint, an auth blueprint and besides that an api blueprint. It can also be useful when you create a new version of your api that breaks backwards compatibility with the first version. In this case you can create a second blueprint for the new version.
You don’t have to create a new blueprint for each api endpoint that you create, you can reuse the api blueprint for each endpoint like:
from flask import Flask, Blueprint
from flask_restful import Api, Resource, url_for
app = Flask(__name__)
core_bp = Blueprint('core', __name__)
api_bp = Blueprint('api', __name__)
api = Api(api_bp)
#core_bp.route('/')
def index():
return 'Index'
class TodoItem(Resource):
def get(self, id):
return {'task': 'Say "Hello, World!"'}
api.add_resource(TodoItem, '/todos/<int:id>')
api.add_resource(User, '/user/<int:id>')
app.register_blueprint(core_bp)
app.register_blueprint(api_bp, url_prefix='/api')
Like this your core application is accessible via '/' and the api via '/api'.

Registering multiple restplus blueprints on same prefix doesn't work

So I'm building an API with Flask-RestPlus and using blueprints to divide the code into smaller chunks, but when trying to register multiple API endpoint, providing same URL prefix, only one blueprint registers.
Blueprint Templates:
from flask import Blueprint
from flask_restplus import Api, Resource
tmpl_bp = Blueprint('templates_api', __name__)
api = Api(tmpl_bp)
ns_tmpl = api.namespace('templates', description='Templates operations')
#ns_tmpl.route('/')
class Templates(Resource):
def get(self):
return "All templates"
def post(self):
return "Added/updated template"
Blueprint Render:
from flask import Blueprint
from flask_restplus import Api, Resource
rend_bp = Blueprint('render_api', __name__)
api = Api(rend_bp)
ns_render = api.namespace('render', description='Render actions')
#ns_render.route('/')
class Render(Resource):
def post(self):
return "Rendering everything"
The main app code, where registering happens:
from flask import Flask, render_template
from api.templates import tmpl_bp
from api.render import rend_bp
app = Flask(__name__)
app.register_blueprint(tmpl_bp, url_prefix="/api/v1")
app.register_blueprint(rend_bp, url_prefix="/api/v1")
#app.route('/')
def home():
return "This is the main page"
The resulting Swagger API:
I was expecting both the Templates and the Render blueprints to be served on /api/v1/ as /api/v1/templates and /api/v1/render respectively. But only one registers every time.
How do I get both blueprints served under the same prefix?
You don't need to use Blueprint, it's enough to use flask_restplus Namespaces.
Flask-RESTPlus provides a way to use almost the same pattern as Flask's blueprint. The main idea is to split your app into reusable namespaces.
from flask import Flask, render_template
from flask_restplus import Resource, Api
from api.templates import tmpl_bp
from api.render import rend_bp
app = Flask(__name__)
api = Api(app)
api.add_namespace(tmpl_bp, path="/api/v1/templates")
api.add_namespace(rend_bp, path="/api/v1/render")
#api.route('/')
def home():
return "This is the main page"
You can find out more details here https://flask-restplus.readthedocs.io/en/stable/scaling.html

Flask route at / returns 404 when used with Flask-Restplus

I have a Flask app which has a Flask-RestPlus API as well as a "/" route. When I try to access "/" however, I get a 404. If I remove the Flask-RestPlus extension, the route works. How do I make both parts work together?
from flask import Flask
from flask_restplus import Api
app = Flask(__name__)
api = Api(app, doc="/doc/") # Removing this makes / work
#app.route("/")
def index():
return "foobar"
This is an open issue in Flask-RestPlus. As described in this comment on that issue, changing the order of the route and Api solves the issue.
from flask import Flask
from flask_restplus import Api
app = Flask(__name__)
#app.route("/")
def index():
return "foobar"
api = Api(app, doc="/doc/")
flask-restplus defines a different way of assigning routes according to their docs:
#api.route('/')
class Home(Resource):
def get(self):
return {'hello': 'world'}
Notice that the api variable is used instead of the app. Moreover, a class is used although I am not 100% sure it is required.

Flask session don't persist data

I have a Javascript application and a Flask application. When the user send data from Js to Flask, I store it on session and it works fine at a specific route:
#app.route(...)
def user(...):
session['name'] = name
print(session['name']) # Works !
But when I tr to get the values on session from another method / route the session is empty:
#app.route(...)
def current():
print(session.keys(), session.values) # Empty !
I have installed Flask Session and set the config to:
'SECRET_KEY': b'...',
'SESSION_TYPE': 'filesystem', # Memcache, null and redis
'SESSION_PERMANENT': False, # True
And then started the Flask application and it not work. I have also try to set session.modified = True after I add some new value to session and still not work.
I have read lots of threads on Stack Over Flow, Reddit, etc; and nothing worked. Tips please ?
TL;DR, enable CORS and credentials support on the back end, and use credentials in the front end code when issuing requests.
I recently ran into a similar issue where I was developing a front end and a back end in separate apps. I noticed that each time I issued a request from the front end client, it would create a new session for each request, which would rapidly bloat the session storage on the back end and made user tracking difficult if not impossible.
I'm assuming that you're Javascript app and Flask app are running separately (i.e., the javascript is not on a template being served by the Flask app and hence the js requests are coming from a different origin).
Suppose we have a simple app with Flask-Session enabled running on port 5000:
from flask import Flask, session
from flask_session import Session
app = Flask(__name__)
SECRET_KEY = "changeme"
SESSION_TYPE = 'filesystem'
app.config.from_object(__name__)
Session(app)
#app.route('/foo')
def foo():
return session.sid
#app.route('/bar')
def bar():
return session.sid
Now if we run the app if we navigate to either route on a browser(e.g., http://localhost:5000/foo), we would get the same session id. If you open another tab, open the developer tools and issue the following command in the console, you'd get a cors error:
// Using fetch, you can use jquery or axios
fetch("http://localhost:5000/foo").then(response => {
return response.text()
}).then(data => {
console.log(data)
})
You can fix this easily by installing Flask-CORS and wrapping your app in the CORS class:
from flask import Flask, session
from flask_session import Session
from flask_cors import CORS
app = Flask(__name__)
SECRET_KEY = "changeme"
SESSION_TYPE = 'filesystem'
app.config.from_object(__name__)
Session(app)
CORS(app)
#app.route('/foo')
def foo():
return session.sid
#app.route('/bar')
def bar():
return session.sid
Now if you run the javascript fetch function above, it prints out a different session id each time the request is invoked, even for the same route. That's because Flask can't track the session unless you're issuing the requests from the same origin or unless you provide some way for flask to identify the session. You can do this from your JS by allowing credentials to be passed:
fetch("http://localhost:5000/foo",
{ credentials: 'include' }).then(response => {
return response.text()
}).then(data => {
console.log(data)
})
However, you will get another CORS error regarding Access-Control-Allow-Credentials. You can fix this in you're Flask app by import the cross_origin decorator, wrapping your routes in the decorator and passing supports_credentials=True to the decorator. The flask code would look something like this:
from flask import Flask, session
from flask_session import Session
from flask_cors import CORS, cross_origin
app = Flask(__name__)
SECRET_KEY = "changeme"
SESSION_TYPE = 'filesystem'
app.config.from_object(__name__)
Session(app)
CORS(app)
#app.route('/foo')
#cross_origin(supports_credentials=True)
def foo():
return session.sid
#app.route('/bar')
#cross_origin(supports_credentials=True)
def bar():
return session.sid
Now flask can track the session by the requester (in this case, the browser running the Javascript app).
I had the same problem using classic post request in html. The session, which was still storing values in previous route, would empty itself after my post request.
I solved this using:
app.config.update(SESSION_COOKIE_SAMESITE="None", SESSION_COOKIE_SECURE=True)
I am sharing this in case others are facing the same issue.

Using REST API to request data from Python script

I have a python script in Apache server, and inside this script there are many types of data.
I want to request those data using REST API.
How can I do it ?
You can use Flask! Here's some documentation: http://flask.pocoo.org/docs/1.0/quickstart/#routing
Basically, you can define your routes through Flask so you can return specific data for specific endpoints that you create.
I suggest you to try to use Flask:
from flask import Flask from flask_restful import Resource, Api
app = Flask(__name__) api = Api(app)
class HelloWorld(Resource):
def get(self):
return {'hello': 'world'}
api.add_resource(HelloWorld, '/')
if __name__ == '__main__':
app.run(debug=True)

Categories