I am looking to serve multiple routes from a single GCP cloud function using python. While GCP Functions actually use flask under the hood, I can't seem to figure out how to use the flask routing system to serve multiple routes from a single cloud function.
I was working on a very small project, so I wrote a quick router of my own which is working well. Now that I'm using GCP Functions more, I'd either like to figure out how to use the Flask router or invest more time on my hand rolled version and perhaps open source it, though it would seem redundant when it would be a very close copy of flask's routing, so perhaps it would be best to add it directly to Flask if this functionality doesn't exist.
Does anyone have any experience with this issue? I'm guessing I'm missing a simple function to use that's hidden in Flask somewhere but if not this seems like a pretty big/common problem, though I guess GCP Functions python is beta for a reason?
Edit: Abridged example of my hand rolled version that I'd like to use Flask for if possible:
router = MyRouter()
@router.add('some/path', RouteMethod.GET)
def handle_this(req):
...
@router.add('some/other/path', RouteMethod.POST)
def handle_that(req):
...
# main entry point for the cloud function
def main(request):
return router.handle(request)
Routing in FlaskThe route() decorator in Flask is used to bind an URL to a function. As a result when the URL is mentioned in the browser, the function is executed to give the result. Here, URL '/hello' rule is bound to the hello_world() function.
Cloud Build then automatically builds your code into a container image and pushes that image to a image registry (either Container Registry or Artifact Registry). Cloud Functions accesses this image when it needs to run the container to execute your function.
App Routing means mapping the URLs to a specific function that will handle the logic for that URL. Modern web frameworks use more meaningful URLs to help users remember the URLs and make navigation simpler. Example: In our application, the URL (“/”) is associated with the root URL.
The point is that if the cloud function runs on example.com/my-function/ I want to ideally use flask to route for /my-function/a and /my-function/b but am currently using my own as I could figure out how to use Flask's routing to do it on the GCP function, since you aren't running an app but just getting a Flask.request object back.
Modern web apps use a technique named routing. This helps the user remember the URLs. For instance, instead of having /booking.php they see /booking/. Instead of /account.asp?id=1234/ they’d see /account/1234/. Routes in Flask are mapped to Python functions. You have already created one route, the ‘/‘ route:
So you can pass parameters to your Flask route, can you pass numbers? The example here creates the route /sale/<transaction_id>, where transaction_id is a number. If you want a flask route with multiple parameters that’s possible. For the route /create/<first_name>/<last_name> you can do this: Flask suports HTTP POST requests.
To bind a function to an URL path we use the app.route decorator. In the below example, we have implemented the above routing in the flask. The hello function is now mapped with the “/hello” path and we get the output of the function rendered on the browser. Step to run the application: Run the application using the following command.
The solution by Martin worked for me until I tried calling request.get_json()
in one of my routes. The end result was the response being blocked in a lower level due to the data stream already being consumed.
I came across this question looking for a solution using functions_framework
in Google Cloud Run. It is already setting up an app
which you can get by importing current_app
from flask.
from flask import current_app
app = current_app
I believe functions_framework
is used by Google Cloud Functions so it should also work there.
Simplified version of @rabelenda's that also works for me:
def main(request):
with app.request_context(request.environ):
try:
rv = app.preprocess_request()
if rv is None:
rv = app.dispatch_request()
except Exception as e:
rv = app.handle_user_exception(e)
response = app.make_response(rv)
return app.process_response(response)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With