Flask: Caching static files (.js, .css) - python

I really could not find any resource on this. So how can I seperate caching of views/functions than static files (i.e. .css,.js)?
I want to cache my static objects for a week, on the other hand I need to cache functions/views for only a few minutes.
When I do following
from flask.ext.cache import Cache
cache = Cache(config={'CACHE_TYPE': 'simple'})
cache.init_app(app)
#cache.cached(timeout=500)
def index():
return render_template('index.html')
then all views, objects' cache time is set to the same value, 500. How to go about it?

I would not server the static files from my python application but try to delegate that to the web server (nginx, apache... ).
Then you could set the time to expire through headers controlling how long should the browser cache them.

Related

How can I fall-through when matching routes in FastAPI

I'm trying to deploy the FastAPI app + front end in one Docker container, so I would not want to add NginX or another web server as it'll complicate the setup.
My routes should look like this:
/ <-- should serve index.html
/{id} <-- should serve index.html, but only when {id} is int
/css/* <-- should serve files from css directory
/... <-- a few other static files (e.g. /service-worker.js)
/api/<whatever> <-- these are the fastAPI routes
So one solution is to match /{id} when it's int and fall-through when it's not. Alternatively if there's a way to just serve everything as static file, except /api calls, that would work too.
Currently I have something like this in my main.py:
#app.get('/api/items')
async def get_items():
return [{'id':1, 'name': 'a'}, {'id':2, 'name': 'b'}]
#app.get('/{id}')
async def root():
with open('html/index.html', 'r') as f:
return HTMLResponse(f.read())
app.mount("/", StaticFiles(directory="dist"), name="static")
But i'm getting 404 when i navigate to "/". I'm serving it with uvicorn main:app.
Any help is appreciated.
As documented, you need to "mount" a static file path. You can set a folder with the name you like and add a prefix on the URL.
It'll then refresh at every page change, so you'll need some way to store access tokens/session data in the client. Also, every single call will go from the client to the API.
Below the link to the documentation about static files:
https://fastapi.tiangolo.com/tutorial/static-files/#static-files

Is the Flask Caching filesystem cache shared across processes?

Let us assume I use Flask with the filesystem cache in combination with uWSGI or gunicorn, either of them starting multiple processes or workers. Do all these processes share the same cache? Or asked differently, do the functions and parameters always evaluate to the same cache key regardless of process pid, thread state etc.?
For instance, consider the following minimal example:
import time
from flask import Flask, jsonify
from flask_caching import Cache
app = Flask(__name__)
cache = Cache(app, config={
'CACHE_TYPE': 'filesystem',
'CACHE_DIR': 'my_cache_directory',
'CACHE_DEFAULT_TIMEOUT': 3600,
})
#cache.memoize()
def compute(param):
time.sleep(5)
return param + 1
#app.route('/')
#app.route('/<int:param>')
def main(param=41):
expensive = compute(param)
return jsonify({"Hello expensive": expensive})
if __name__ == '__main__':
app.run()
Will www.example.com/41 just take 5 seconds once and then (for 3600 seconds) be available instantly regardless of the uWSGI or gunicorn workers?
If i run it locally on my machine, the cache is stable across different processes as well as even different restarts of the entire server.
I am finding that the flask-caching filesystem cache is kept per-worker. Simple example I just tried in my app (4 workers):
#app.route("/product/<id>", methods=["GET"])
#app.cache.cached()
def product(id):
product = Product.from_id(id)
app.pp.pprint(product.get_data())
I'm re-loading the page that calls that view and I see the pprint output 4 times in the console, then no more after that.

modify flask url before routing

My Flask app has url routing defined as
self.add_url_rule('/api/1/accounts/<id_>', view_func=self.accounts, methods=['GET'])
Problem is one of the application making queries to this app adds additional / in url like /api/1//accounts/id. It's not in my control to correct the application which makes such queries so I cant change it.
To resolve this problem currently I have added multiple rules
self.add_url_rule('/api/1/accounts/<id_>', view_func=self.accounts, methods=['GET'])
self.add_url_rule('/api/1//accounts/<id_>', view_func=self.accounts, methods=['GET'])
There are number of such routes and it's ugly workaround. Is there a way in flask to modify URL before it hits the routing logic?
I'd normalise the path before it gets to Flask, either by having the HTTP server that hosts the WSGI container or a proxy server that sits before your stack do this, or by using WSGI middleware.
The latter is easily written:
import re
from functools import partial
class PathNormaliser(object):
_collapse_slashes = partial(re.compile(r'/+').sub, r'/')
def __init__(self, application):
self.application = application
def __call__(self, env, start_response):
env['PATH_INFO'] = self._collapse_slashes(env['PATH_INFO'])
return self.application(env, start_response)
You may want to log that you are applying this transformation, together with diagnostic information like the REMOTE_HOST and HTTP_USER_AGENT entries. Personally, I'd force that specific application to generate non-broken URLs as soon as possible.
Look at your WSGI server documentation to see how to add in extra WSGI middleware components.

Using render_templete and static file, which one is faster in Flask

I'm developing an web app using Flask in Heroku. My web will have k news pages. Information for each page is stored in database. When user make a request in web browser, the returned page can be generated using render_templates() in Flask.
The problem is when all users request same page, render_templates() will be called multiple times for the same page => kind of wasting resources to do the same thing
I curious whether I should use render_templates() or I should generate k static pages and use there static file instead?
You can use Flask-Cache package.
Support built-in cache backends like dictionary, file system, memcached, redis, and also custom cache backends.
Example:
#cache.cached(timeout=50)
def index():
return render_template('index.html')
.
#cache.memoize(timeout=50)
def big_foo(a, b):
return a + b + random.randrange(0, 1000)
.
#cache.cached(timeout=50)
def big_foo():
return big_bar_calc()
Also another option [beside that] is using front page caching, like varnish.

How to access wsgi params from a request inside a middleware and a flask request without side effect?

I need to read some values from the wsgi request before my flask app is loaded. If I read the url from the wsgi request I can access the file without any issues once the flask app is loaded (after the middleware runs).
But if I attempt to access the params it seems to remove the post data once the flask app is loaded. I even went to the extreme of wrapping the wsgi request with a special Webob Request to prevent this "read once" problem.
Does anyone know how to access values from the wsgi request in middleware without doing any sort of side effect harm to the request so you can get post data / file data in a flask app?
from webob import Request
class SomeMiddleware(object):
def __init__(self, environ):
self.request = Request(environ)
self.orig_environ = environ
def apply_middleware(self):
print self.request.url #will not do any harm
print self.request.params #will cause me to lose data
Here is my flask view
#app.route('/')
def hello_world():
from flask import request
the_file = request.files['file']
print "and the file is", the_file
From what I can tell, this is a limitation of the way that WSGI works. The stream needs only be consumable once (PEP 333 and 3333 only require that the stream support read* calls, tell does not need to be supported). Once the stream is exhausted it cannot be re-streamed to other WSGI applications further "inward". Take a look at these two sections of Werkzeug's documentation for more information:
http://werkzeug.pocoo.org/docs/request_data/
http://werkzeug.pocoo.org/docs/http/#module-werkzeug.formparser
The way to avoid this issue is to wrap the input stream (wsgi.input) in an object that implements the read and readline methods. Then, only when the final application in the chain actually attempts to exhaust the stream will your methods be run. See Flask's documentation on generating a request checksum for an example of this pattern.
That being said, are you sure a middleware is the best solution to your problems? If you need to perform some action (dispatch, logging, authentication) based on the content of the body of the request you may be better off making it a part of your application, rather than a stand-alone application of its own.

Categories

Resources