Search code examples
pythonfirebaseflaskfirebase-tools

Flask API keeps returning 404 for GET requests after deploying locally using functions framework


I am new to flask and firebase, and I am trying to develop a social networking app. I am starting with the API for the profile creation, which works perfectly when run it. However, when I deploy it locally (functions-framework --target=run_app --debug) and try to use the entry point I have defined to make get requests, I get a 404 error. My firebase works.

Here's my main.py code containing my APIs

# Required imports

import os
import functions_framework
from flask import Flask, request, json, jsonify
from firebase_admin import credentials, firestore, initialize_app

# Initialize Flask app

flaskapp = Flask(__name__)

# Use credentials to initialize firebase_admin

cred = credentials.Certificate("finalProject.json")
default_app = initialize_app(cred)
db = firestore.client()

# Define the entry point for the cloud function

@functions_framework.http
def run_app(request):
\# Check the request method
    if request.method == 'POST' and 'name' in request.get_json():
\# Call the register_user function
        return register_user()
    elif request.method == 'GET' and 'userId' in request.args:
\# Call the view_user function
        return view_user(request.args.get('userId'))
    elif request.method == 'PATCH' and 'userId' in request.args:
\# Call the edit_user function
        return edit_user(request.args.get('userId'))

    # Endpoints

# Create user Profile

# @flaskapp.route('/profile', methods=\['POST'\])

def register_user():

# handle request

# View user profile

# @flaskapp.route('/profile/\<userId\>', methods=\['GET'\])

def view_user(userId):

# handle request

# Edit user profile

# @flaskapp.route('/profile/\<userId\>', methods=\['PATCH'\])

def edit_user(userId):

# handle request

# Post

# Feed

# Run Flask app

port = int(os.environ.get('PORT', 8080))
if __name__ == '__main__':
    flaskapp.run(threaded=True, host='0.0.0.0', port=port)

And the postman request I am making with the error are in the attached screenshot.

I tried to test in the terminal using curl "http://localhost:8080/?userId=11112022" and got a curl not found error


Solution

  • I think only functions decorated with @functions_framework.http get mapped to an endpoint. To deploy a full Flask app with routing, etc., to a single endpoint, I got this to work:

    # Required imports
    
    import os
    import functions_framework
    from flask import Flask, request, json, jsonify
    from firebase_admin import credentials, firestore, initialize_app
    
    # Initialize Flask app
    
    flaskapp = Flask(__name__)
    
    # Use credentials to initialize firebase_admin
    
    # cred = credentials.Certificate("finalProject.json")
    # default_app = initialize_app(cred)
    # db = firestore.client()
    
    # Define the entry point for the cloud function
    
    @functions_framework.http
    def run_app(request):
        with flaskapp.request_context(request.environ):
            return flaskapp.full_dispatch_request()
    
    # Endpoints
    
    # Create user Profile
    @flaskapp.route('/profile', methods=['POST'])
    def register_user():
        # handle request
        print("register_user")
        return "register_user"
    
    # View user profile
    @flaskapp.route('/profile/<userId>', methods=['GET'])
    def view_user(userId):
        # handle request
        print("view_user")
        return "view_user"
    
    # Edit user profile
    @flaskapp.route('/profile/<userId>', methods=['PATCH'])
    def edit_user(userId):
        # handle request
        print("edit_user")
        return "edit_user"
    
    # Run Flask app
    port = int(os.environ.get('PORT', 8080))
    if __name__ == '__main__':
        flaskapp.run(threaded=True, host='0.0.0.0', port=port)
    

    (I didn't handle query params, but you can do that in your route handlers.)

    Then you can access your routes:

    % curl "http://localhost:8080/profile/11112022"           
    view_user%
    % curl "http://localhost:8080/profile/11112022" -X 'PATCH'
    edit_user%
    % curl "http://localhost:8080/profile" -X 'POST'          
    register_user%
    

    Flask experts can weigh in if this is a bad idea for some reason!