I am using Flask as a web framework. I have defined an html resource within my service worker definition like below
var urlsToPrefetch = [
'webapp/templates/practice/foopage.html',
];
This works ok.
Using Flask Blueprints, foopage.html is rendered to the user when they visit https://example.com/practice/foopage. The Blueprint name is "practice".
The corresponding route is below:
#practice.route('/foopage', methods=['GET'])
def foopage():
return render_template('practice/foopage.html')
The problem is that within the service worker's fetch eventListener shows the event.request.url as https://example.com/practice/foopage
This is not found in the cache because I had to define the html file using its actual path.
Is there a way to map filenames to the routes used in the application? Or do I need to think about this differently?
You're confusing paths to templates, which is a server side thing, with urls that get routed to views. As far as the client can tell, the response from /foopage is the document, it doesn't matter how that document was generated on the server side.
Specify the url to the resource, /foopage, as the thing to prefetch.
Related
I want to make a simple serverless backend, so I'm trying to use google cloud functions with flask routing.
I'm trying to test a simple code, but it's not working. The following source always returns 404 errors.
from flask import Flask, make_response
class Services:
pass
def create_app(test_config = None):
app = Flask(__name__)
services = Services
create_endpoints(app, services)
return app
def create_endpoints(app, services):
#app.route("/test", methods=['GET'])
def test():
return make_response('Test worked!', 200)
function URL : ######.cloudfunctions.net/test1
I tried "######.cloudfunctions.net/test1" and "######.cloudfunctions.net/test1/test", but it always returns 404 error.
can I use flask routing ?
I think that it is a not fancy way to add a router to a cloud function, but it works.
I used the property "path" of the object "request"( this is a flask.request object) to read the path after the domain in the requested URL
from flask import abort
def coolrouter(request):
path = (request.path)
if (path == "/test"):
return "test page"
elif (path == "/home" or path =="/"):
return "ḧome page"
else:
abort (404)
keep in mind that cloud functions are designed to be a one shot services, that means that is not possible to save session variables or other things since this is service is ephemeral.
If you want upload a complete site I recommend you to use App Engine, which is a Fully managed serverless application platform.
Google now has api gateway which would allow you to have a single endpoint to handle all of your routes. See goblet as an easy way to manage and deploy your api to api gateway
I agree with all the answers given here, but I want to elaborate a bit from my experience. Since Cloud Functions are designed for single-purpose use only. It can process HTTP requests and events from pubsub, storage etc. When using API gateway or Cloud Endpoints in front of your Cloud Functions, you can offload authentication and routing, so your code has only one responsibility.
However, the downside that you will never get rid of the cold-start problem when using Cloud Functions as an API. Serving requests can sometimes last up to 2-10 seconds or more, depending on the size of your code and programming language. So you are probably better of with Google App Engine or something that you can reserve to be "always there".
I am currently experimenting with the Cloud Function + API Gateway setup. I am routing GET, POST and DELETE methods for one object to the same cloud function. So I am basically trying to let it be single-purpose in the way that one function only handles requests for only one object. This could easily be accomplished with a switch case on the method used, so no routing is needed. A schematic example:
Cloud function one:
Path: /blogs
Methods: GET, POST, DELETE
Purpose: Handles all actions on blog objects
Cloud function two:
Path: /posts
Methods: GET, POST, DELETE
Purpose: Handles all actions on post objects
According to the official documentation:
Cloud Functions is a serverless execution environment for building and
connecting cloud services. With Cloud Functions you write simple,
single-purpose functions that are attached to events emitted from your
cloud infrastructure and services. Your function is triggered when an
event being watched is fired.
Python Quickstart Cloud Functions
Within an app composed of multiple microservices run via docker-compose, I need a way to make a request from one container (app via flask & requests), directly to the other (chart/django):
This is a simplified version of what I'm attempting.
routes.py:
#APP.route('/post_data', methods=['POST'])
def post_data():
post_data = request.get_json()
response = requests.post('http://chart_app_1:8080/json/', data=post_data)
return response.text
The response I get is an error message:
django.core.exceptions.DisallowedHost: Invalid HTTP_HOST header: 'chart_app_1:8080'. The domain name provided is not valid according to RFC 1034/1035
I'm able to make exactly this kind of request to other containers running flask apps, with no problems. I don't have any control over whether or not we use Django for this particular microservice though.
It seems that this might be because the hostname has an underscore in it: see this post. Is there a way around this? It seems like it must be possible to make a simple request between containers.
In the docker-compose file, modify the service name for avoiding underscores in the Django service.
That's the only way that I know for avoiding the error as it's not a Docker limitation.
I'm trying to develop a PWA for our sites. In production and staging, we serve everything from one domain. However, in development on a local machine we serve HTML from one port using Django server eg
http://localhost:8000
And the assets (including JS) using Grunt server from another port:
http://localhost:8001
The problem is that the scope of the service workers is therefore only limited to assets, which is useless, I want to offline-cache pages on the 8000-port origin.
I have somewhat been able to go around this by serving the service worker as a custom view in Django:
# urls.py
url(r'^(?P<scope>.*)sw\.js', service_worker_handler)
# views.py
def service_worker_handler(request, scope='/'):
return HttpResponse(render_to_string('assets/sw.js', {
'scope': scope,
}), content_type="application/x-javascript")
However, I do not think this is a good solution. This code sets up custom routing rules which are not necessary for production at all.
What I'm looking for is a local fix using a proxy, or something else that would let me serve the service worker with grunt like all the other assets.
I believe this resource can be of help to you: https://googlechrome.github.io/samples/service-worker/foreign-fetch/
Basically you host the Service worker on the port 8001 and the server handles it as shown in the example.
Then you fetch it from there.
The Foreign fetch is described more in details here: https://developers.google.com/web/updates/2016/09/foreign-fetch
I'm struggling to find the proper way to setup my flask routes when moving my app to being hosted in a subdirectory. I've read a bunch of great answers on this subject, most notably this answer on adding a prefix to all routes. However, I think my situation is slightly different. I want to ONLY prefix the URLs I generate with url_for, not respond to those URLs. Is there a way to do this?
For example, assume my flask app is hosted at http://www.acme.com/tools/. The main acme.com domain is setup with a proxy pass to pass all requests from /tools/* to my app. So, my app only sees requests like /, /product_1/ even though the full URL is http://www.acme.com/tools/product_/, etc. So, my app.route rules can use / as the base route. The problem is I use url_for everywhere and I want the urls generated to be the full url like /tools/product_1, not /product_1. Is there a way to achieve this?
I've tried using blueprints but those will make the #app.route and url_for respond to /tools/xyz. Is there a more simple solution to this issue or is this a non-standard way to handle this issue?
I would take a look at this snippet: http://flask.pocoo.org/snippets/35/
I'm not sure I love the idea of modifying your WSGI environment as the only solution to this problem. You can always wrap url_for. (note that this won't work for _external=True)
def my_url_for(*args, **kwargs):
return '/tools' + url_for(*args, **kwargs)
Be sure to set your APPLICATION_ROOT to /tools so that cookies are only accessible from the app.
I found a different way to handle this without having to provide a wrapper for url_for. I'm using a custom routing rule to append the prefix. This means none of the app.route decorator calls have to be changed and all calls to url_for will automatically get the prefix added. Are there any caveats I'm missing by overriding the url_rule_class?
Add the following to your __init__.py after setting up your app.
from werkzeug.routing import Rule
class PrefixRule(Rule):
def build(self, *args, **kwargs):
domain_part, url = super(PrefixRule, self).build(*args, **kwargs)
return domain_part, u'%s%s' % (app.config['PREFIX'], url)
app.url_rule_class = PrefixRule
I am attempting to build a MongoDB-backed Flask application which serves from the same endpoints:
A HTML web interface by default
A JSON response if Content-Type == application/json
The idea is that both a user consuming my application with a browser and a service consuming my API programatically can both hit http://myapp.com/users/12345 The former is served a HTML response and the latter is served a JSON response.
As I understand this is in keeping with 'pure' REST, in contrast to the tradition of serving the API from a separate path such as http://myapp.com/api/users/12345.
There is no discussion of views in the Eve docs, other than to say that results are served as JSON by default and XML if requested.
Is there any clean way to override this behaviour such that:
The standard Eve JSON response is served if Content-Type == application/json
Otherwise, a view applies a template to the data returned by Eve to generate a HTML response?
This seems like it would be an elegant means of creating an application which is both RESTful and DRY.
You could look at the Eve-Docs extension which implements a HTML /docs endpoint on top of an existing, Eve-powered, MongoDB REST Service.
Remember Eve is a Flask application (a subclass actually), so everything you can do with Flask you can do with Eve too (like decorate rendering functions etc.)
UPDATED: Here's a little example snippet which adds a custom /hello endpoint to a Eve powered API (source). As you can see is pretty much identical to a standard Flask endpoint:
from eve import Eve
app = Eve()
#app.route('/hello')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run()