Routing issue on Single Page Application on Elastic Beanstalk - python

Using Flask as the web server, and Angular as my SPA in a /static directory. I implemented a catch-all end point on my Flask app to try solve an issue where users were being given a 404 when they refresh a page, but it did not solve the issue. Does anyone know how to fix this?
The catch-all looks like:
#application.route('/', defaults={'path': ''})
#application.route('/static/<path:path>')
def main(path):
return render_template('index.html')
I also implemented a redirect if a 404 is thrown, but this hasn't helped either:
#application.errorhandler(Exception)
#cross_origin()
def main_404(*args, **kwargs):
logger.info("Routing passed to web application...")
return render_template('index.html')

Try using error handlers if you want to catch errors:
#application.errorhandler(404)
def page_not_found(error):
app.logger.error('Page not found: %s', (request.path))
return render_template('404.html'), 404

Related

How do I implement a ReactJS app into my Flask app?

I have a ReactJS frontend with multiple routes. e.g.: /, /example1, example1/example2/example3/example4.
I have used the react-build script to make production build of the ReactJS app. Now I'm trying to incorporate the ReactJS app with the Flask app.
This is what I have so far on my Flask routes:
app = Flask(__name__, static_folder="./build", static_url_path="")
CORS(app)
app.secret_key = secret_key
#app.route("/", defaults={"path": ""})
#app.route("/<path:path>")
def serve(path):
return app.send_static_file("index.html")
This works, but not for all routes. For example, /example1 and /example1/example2 work. But /example1/example2/example3 doesn't work. Any ideas? Thanks.
EDIT:
It turns out that /example1/example2 does not work, meaning that the issue is to do with custom routes, which aren't predefined. All routes which I have specifically defined work, but the dynamically made ones don't.
https://blog.miguelgrinberg.com/post/how-to-deploy-a-react-router-flask-application - this might help you for now, the tutorial has modified the 404 exception handler (Not really an elegant solution but works).
#app.errorhandler(404)
def not_found(e):
return app.send_static_file('index.html')

Catch-All URL example in flask-restful also catching /

There is a catch-all URL example for Flask:
from flask import Flask
app = Flask(__name__)
#app.route('/', defaults={'path': ''})
#app.route('/<path:path>')
def catch_all(path):
return 'You want path: %s' % path
if __name__ == '__main__':
app.run()
Decorators can be translated to the following to code look more similar to Flask-RESTful achieving the same functionality:
app.add_url_rule('/', 'catch_all', catch_all, defaults={'path': ''})
app.add_url_rule('/<path:path>', 'catch_all', catch_all, defaults={'path': ''})
If I'm right, this can be further translated to an equivalent Flask-RESTful app (at least debuging shows it creates the same URL routes):
class RESTapp(Resource):
def get(self, path):
# do get something
api.add_resource(RESTapp, '/', '/<path:path>', defaults={'path': ''})
The problem is that this app redirects all URLs to / and I can not get the requested path in get() function. I want to handle all paths ( / and '/') in the same function as in Flask, but using Flask-RESTful.
Similar questions:
Catch-All URL in flask-restful The Asker does not want to catch / or at least not in the same functions as other URL-s.
Flask restful API urls The Answerer proposes two classess as two resources. I have to initialize the class through resource_class_kwargs keyword argument and I want to keep only one instance, so it will not be good for me.
What I've tried:
Create two add_resource calls for the same class. It end with error.
Debug add_resource. It shows that it creates a resource view function from the Endpoint and that is given to the add_url_rule function. Else it works the same as the two subsequent add_url_rule functions.
By trial and error I've figured out the solution, which is neither documented nor looks like to the expected way of doing it (simmilarly as in Flask, showed in the question).
One must supply a Pythonic default argument to get() and other functions: get(stuff='DEF_VAL')
Full example which is working:
from flask import Flask
from flask_restful import Api, Resource
app = Flask(__name__)
api = Api(app)
class RESTapp(Resource):
#staticmethod
def get(path=''): # <-- You should provide the default here not in api.add_resource()!
return 'You want path: \'%s\'' % path # do get something
api.add_resource(RESTapp, '/', '/<path:path>') # Here just the URLs must be the arguments!
if __name__ == '__main__':
app.run()

How to redirect to default 404 page with flask-restful

My resource is shown at bottom and it is hooked to /jobs/ using
api.add_resource(JobAPI, '/jobs/<int:job_id>')
I also have a custom 404 page. If the requested job_id doesn't exist, how can I redirect to the custom 404 page? I tried to use abort(404) but it only shows some JSON message
{
"message": "The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. You
have requested this URI [/jobs/1] but did you mean /jobs/
?" }
I also tried to return redirect() but since marshal_with has been used, it doesn't redirect but insists on returning a job instance.
class JobAPI(Resource):
"""
Simple job
"""
#marshal_with(job_fields)
def get(self, job_id):
job = Job.query.get(job_id)
if job is None:
abort(404)
# flash('Job does not exist.')
# return redirect(url_for('home.index'))
return job
Try setting ERROR_404_HELP=False in your flask application configuration, worked for me.
Flask-Restful Doc link here
As correctly mentioned in the previous answer set the flask object configuration ERROR_404_HELP to False in the file where you have created your flask object.
app = Flask(__name__)
app.config['ERROR_404_HELP'] = False

Flask View Testing General and with Subdomains

I'm working on testing the views that I have for a Flask application and I'm having some issues. I use a csrf token for my form submissions and I also use subdomains for logging in and I was wondering how to test for that as well. If anyone has any experience or could give me an example or some direction, I would appreciate it because I've already gone through all of the guides and documentation I could fine.
Below is what I'm trying to test and the test I'm running.
#app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
try:
#acts as redirect, but with subdomain
return redirect_subdomain('login', request.url, request.form['subdomain'])
except OrganizationDoesNotExistException:
return render_template('login.html', subdomain=False)
return render_template('login.html', subdomain=False)
These are the tests I'm running just to get started. It only accepts a subdomain (organization) that will be used to redirect the user to the subdomain specific login, which works, I just want to know how to write tests for the future:
def test_login(self):
rv = self.login('test')
print(rv.data.decode('utf-8'))
pass
def login(self, organization):
return self.app.post('/login', data=dict(
organization=organization
), follow_redirects=True)
I know these are basic tests and don't really test much, but I still get errors and I want to know how to go about testing views in general and when there are subdomains involved, like in my case.
In order to be able to create unittests for a flask app using subdomain routing, the test_client() function can be used. For this to work, you will need to set the allow_subdomain_redirects attribute on the test_client object to True.
Here is an example test case for a flask app using subdomain routing.
import yourapp
import unittest
class FlaskTestCase(unittest.TestCase):
def setUp(self):
self.app = yourapp.app.test_client()
self.app.allow_subdomain_redirects = True
def test_request(self):
r = self.app.get('http://subdomain.domain.com/route/', query_string='key=value')
self.assertEquals(r.data, known_result)

Flask view function catch all URLs except one small subset

I'm writing a proxy in Flask. The proxy should forward all requests except one small subset, for which some additional checks should be performed.
Since there is a variety of routes I found this example in the docs
to match all URLs:
from flask import Flask
app = Flask(__name__)
#app.route('/', defaults={'path': ''})
#app.route('/<path:path>')
def catch_all(path):
return 'You want path: %s' % path
if __name__ == '__main__':
app.run()
What I'm wondering is what is the best way to have one view function that handles this subset of routes, and another view function that handles all others ?
Flask has decorators to perform action before handling the request.
#app.after_request
def catch_all(response):
# * additional checks here *
You can stop the normal handling by returning data
If any of these function returns a value it’s handled as if it was the return value from the view and further request handling is stopped.
It is often use for authentication or permission checks.

Categories