Reputation: 2897
I am exploring Google Cloud Functions in Python to write HTTP triggered functions. I have a main.py
with all my triggered functions structured like in this post, but would like to be able to wrap in some endpoints. On nodejs, one could do so like in this post using Express
, and on Python, very similarly using Flask
.
I have attempted to dabble by wrapping my Cloud Functions using Flask, but Google will bring me to Google's authentication page. My code as follows:
from flask import Flask, jsonify, request
# Initialize Flask application
application = Flask(__name__)
@application.route('/some/endpoint/path', methods=['GET'])
def predict():
inputs = request.args.get('inputs')
//Some logic...
response_object = {}
response_object['statusCode'] = 200
response_object['results'] = results
return jsonify(response_object)
Is there a way to wrap the python cloud functions in such a way to acheive something like this?
https://us-central1-my-project.cloudfunctions.net/some
https://us-central1-my-project.cloudfunctions.net/some/endpoint
https://us-central1-my-project.cloudfunctions.net/some/endpoint/path
Upvotes: 1
Views: 1970
Reputation: 21520
Cloud Functions is designed to be used as a single endpoint. You might consider using Cloud Run instead, as it's more suited towards applications with multiple routes, and has many of the same benefits as Cloud Functions.
If you're dead set on using Cloud Functions, something like the answer at Injecting a Flask Request into another Flask App should work, but it's not ideal.
Upvotes: 0
Reputation: 1562
I believe you are getting the authentication Google screen because you are trying to access the base url for Cloud Functions on your project.
With HTTP Cloud Functions the trigger url is usually https://[REGION]-[PROJECT_ID].cloudfunctions.net/[FUNCTION_NAME]
, so any routes would need to follow another slash after the function name.
That being said, I found this post where the solution provided manage to set routes within the same main.py file to access the endpoints from a single Cloud Function. I had to adapt some things, but in the end it worked for me.
The following is the source code I tested at my end:
import flask
import werkzeug.datastructures
app = flask.Flask(__name__)
@app.route('/')
def root():
return 'Hello World!'
@app.route('/hi')
def hi():
return 'Hi there'
@app.route('/hi/<username>')
def hi_user(username):
return 'Hi there, {}'.format(username)
@app.route('/hi/<username>/congrats', methods=['POST'])
def hi_user_congrat(username):
achievement = flask.request.form['achievement']
return 'Hi there {}, congrats on {}!'.format(username, achievement)
def main(request):
with app.app_context():
headers = werkzeug.datastructures.Headers()
for key, value in request.headers.items():
headers.add(key, value)
with app.test_request_context(method=request.method, base_url=request.base_url, path=request.path, query_string=request.query_string, headers=headers, data=request.form):
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)
This defined the following routes within a single Cloud Function:
https://[REGION]-[PROJECT_ID].cloudfunctions.net/[FUNCTION_NAME]
https://[REGION]-[PROJECT_ID].cloudfunctions.net/[FUNCTION_NAME]/hi
https://[REGION]-[PROJECT_ID].cloudfunctions.net/[FUNCTION_NAME]/hi/<username>
https://[REGION]-[PROJECT_ID].cloudfunctions.net/[FUNCTION_NAME]/hi/<username>/congrats
And the following was the command used to deploy this function:
gcloud functions deploy flask_function --entry-point main --runtime python37 --trigger-http --allow-unauthenticated
Upvotes: 3