Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to serve multiple routes on the same Url : Port #98

Closed
martindufort opened this issue Nov 23, 2020 · 6 comments · Fixed by #99
Closed

How to serve multiple routes on the same Url : Port #98

martindufort opened this issue Nov 23, 2020 · 6 comments · Fixed by #99
Labels
enhancement New feature or request

Comments

@martindufort
Copy link

martindufort commented Nov 23, 2020

Hi,

I'm trying to serve multiple routes from the same Host / Port combination for local testing.

Each of these routes would point to a specific target.
All cloud functions (on GCloud) are sharing the same hostname.
So I would like to replicate this environment as much as possible

Is this possible ? I have not seen anything in the documentation to help me perform this setup.
I would like to serve something like this:

http://localhost:8080/doFunctionA
http://localhost:8080/doFunctionB
http://localhost:8080/doFunctionC

Thanks

@di
Copy link
Member

di commented Nov 23, 2020

Hi @martindufort, thanks for filing an issue.

If I understand correctly, you have multiple individual functions and you'd like to be able to serve them all simultaneously. You do not have a single function that you're trying to serve multiple endpoints from, is that correct?

If so, you're correct that the Functions Framework doesn't currently support that, but I think it would probably be a reasonable feature request. How would you imagine invoking the framework with multiple targets?

@di di added the enhancement New feature or request label Nov 23, 2020
@di
Copy link
Member

di commented Nov 23, 2020

Also, a follow-up question: are these all the same function type, or are they a mix of HTTP and Background functions?

@martindufort
Copy link
Author

Hi @di, thanks for the quick reply.

A little bit of background: We have a server component to our solution which is being managed by the GCloud API Gateway connected to a number of cloud functions (http-triggered)

Within our Openapi description document, each route (URL Path) is directed to a specific Cloud Function.

paths:
  /account/make:
    post:
      operationId: makeAccount
      x-google-backend:
        address: https://us-central1-xxxx.cloudfunctions.net/makeAccount

When we deploy them, they are all accessible from the same host but with a specific URL path.

So I would like to have a similar configuration for local testing where we would serve all these functions simultaneously on the same host:port combination.

Then we will be able to mimic the API Gateway functionality and test those locally.

For the configuration, I was thinking we could supply a .yaml file that would describe the mapping between the URL-Path and the (source file/target function) locally.

Let me know if this is clear enough.

@di
Copy link
Member

di commented Nov 25, 2020

Thanks for the replies @martindufort! Makes sense.

This is probably not something the Function Frameworks will support directly, however I created #99 to show an example of using skaffold, minikube, Cloud Buildpacks, and the Function Framework to run multiple functions on the same host and route based on some path.

I think this should satisfy your use case, please take a look and let me know!

@martindufort
Copy link
Author

Hi @di, I had a look at #99 and it looks good.
However this is involving too many external dependencies for us. And we want to manage them at a minimum.

We might try to fork and change some of the functionality to provide a lighter mechanism for our needs.
Will report back if we go that route.

Thanks for your reply.

@av1m
Copy link

av1m commented Mar 29, 2022

I think you can bypass using this method, an example :

# main.py
from flask import Flask, request

app = Flask(__name__)


@app.route("/", methods=["GET"])
def main():
    return "<h1>Hello World</h1>", 200


@app.route("/user/<string:id>", methods=["POST", "GET"])
def user(id):
    if request.is_json:
        return {"id": id, **request.json}, 200
    return {"id": id}, 200


def entrypoint(request):
    # Create a new app context for the app
    internal_ctx = app.test_request_context(
        path=request.full_path, method=request.method
    )
    # Copy the request headers to the app context
    internal_ctx.request = request
    # Activate the context
    internal_ctx.push()
    # Dispatch the request to the internal app and get the result
    return_value = app.full_dispatch_request()
    # Offload the context
    internal_ctx.pop()
    # Return the result of the internal app routing and processing
    return return_value

Run this script with the following command :

functions_framework --target entrypoint

You can also see this example with blueprints https://github.com/av1m/functions-multiple-endpoints.git

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants