2
votes

Is there a way to inject a Flask request object into a different Flask app. This is what I'm trying to do:

app = flask.Flask(__name__)

@app.route('/foo/<id>')
def do_something(id):
  return _process_request(id)

def say_hello(request):
   # request is an instance of flask.Request.
   # I want to inject it into 'app'

I'm trying this with Google Cloud Functions, where say_hello() is a function that is invoked by the cloud runtime. It receives a flask.Request as the argument, which I want to then process through my own set of routes.

I tried the following, which doesn't work:

def say_hello(request):
    with app.request_context(request.environ):
        return app.full_dispatch_request()

This responds with 404 errors for all requests.

Edit:

The simple way to implement say_hello() is as follows:

def say_hello(request):
    if request.method == 'GET' and request.path.startswith('/foo/'):
        return do_something(_get_id(request.path))
    flask.abort(404)

This essentially requires me to write the route matching logic myself. I'm wondering if there's a way to avoid doing that, and instead use Flask's built-in decorators and routing capabilities.

Edit 2:

Interestingly, dispatching across apps work locally:

app = flask.Flask(__name__)

# Add app.routes here

functions = flask.Flask('functions')

@functions.route('/', defaults={'path': ''})
@functions.route('/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE'])
def catch_all(path):
    with app.request_context(flask.request.environ):
        return app.full_dispatch_request()

if __name__ == '__main__':
    functions.run()

But the same technique doesn't seem to work on GCF.

1
you mean multiple instances of an app? other than that, you might be able to get away with requests and actually making a request to a view of the other app you have. - senaps
Not quite sure I follow you. I added some more details to the post, further explaining what I'm attempting to do. - Hiranya Jayathilaka

1 Answers

0
votes

I wouldn't recommend this method, but this is technically possible by abusing the request stack and rewriting the current request and re-dispatching it.

However, you'll still need to do some type of custom "routing" to properly set the url_rule, as the incoming request from GCF won't have it (unless you explicitly provide it via the request):

from flask import Flask, _request_ctx_stack
from werkzeug.routing import Rule

app = Flask(__name__)

@app.route('/hi')
def hi(*args, **kwargs):
    return 'Hi!'

def say_hello(request):
    ctx = _request_ctx_stack.top
    request = ctx.request
    request.url_rule = Rule('/hi', endpoint='hi')
    ctx.request = request
    _request_ctx_stack.push(ctx)
    return app.dispatch_request()