Search code examples
htmlflaskgoogle-cloud-platformgoogle-app-engineweb-applications

Handling POST request form with Flask app and Google App Engine


I am working on my first web app using Flask as the backend but I am having some issues with a form with a POST request. The form works fine on my local machine, but when I deploy it to GCPs app engine it does not work. Whenever I click the submit button for the form - the page just loads indefinitely.

When looking at the logs I do not even see a POST request go through. I added some debugging prints to the Flask code, and the one at the very start of the POST function does not show up in the logs. This makes me think it is something to do with how the form / POST request is set up.

Does anyone know whats going on? Do I have to do some CSRF stuff (saw that in another thread)? Is there something else I have to do when handling POST requests on App Engine? Maybe some configuration in the app.yaml file? I am pretty stumped because it doesn't look like the POST request is even going through so not sure where to keep looking.

Some more context: The app allows user to create a Spotify playlist from Spotify links sent in an iMessage group chat.

The bare bones of my form is below. It has a file input, text input, and a submit button.

<form method="post" enctype="multipart/form-data" id="chatTracksForm" class="playlist-form">
        <h2 class="mainHeaders">1. Upload file</h2>
        <input type="file" name="file" id="file" accept=".db" class="input-file">
      
        <h2 id="header2" class="mainHeaders">2. Enter name</h2>
        <input type="text" id="chat_name" name="chat_name" placeholder=" Group chat name">

        <input type="submit" value="Create Playlist" id="btnSub">
</form>

Here is the Flask code that handles the form submission. Cleaned up some the debugging print but otherwise this is pretty bare.

@app.route('/', methods=['POST'])
def create_playlist():
    print("YO")
    cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session)
    auth_manager = spotipy.oauth2.SpotifyOAuth(cache_handler=cache_handler)
    if not auth_manager.validate_token(cache_handler.get_cached_token()):
        return redirect('/')
    sp = spotipy.Spotify(auth_manager=auth_manager)

    file = request.files['file']
    if file:
        filename = secure_filename(file.filename)
        filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
        output = file.save(filepath)

        chat_name = request.form['chat_name']
        playlist = PlaylistFromiMessage(sp, filepath)

        ##### CREATING PLAYLIST LOGIC ##### # Getting messages - if messages return 0 that means error with input chat_name
        messages = playlist.get_messages_from_groupchat(chat_name)
        if len(messages) == 0:
            error_message = f"No messages for {chat_name} - try another group chat"
            return render_template("create_playlist.html", error_message=error_message)

        # Creating playlist
        playlist_id = playlist.create_new_playlist_if_not_exists(chat_name)
        # Getting spotify ids for messages
        spot_ids = playlist.get_spotify_ids(messages)
        # Adding tracks to playlist
        tracks_added = playlist.add_tracks_to_playlist(playlist_id, spot_ids)

        # Return success page with link to spotify playlist
        playlist_obj = sp.playlist(playlist_id)
        spotify_playlist_link = playlist_obj["external_urls"]["spotify"]
        return render_template('success.html', playlist_url=spotify_playlist_link, tracks_added=tracks_added)

    else:
        return redirect('/')

Solution

    1. If you're saying the Flask code you've posted is going to handle your form submission, then add action = "/" to your form (see action attribute)

    2. Since your code has only a POST method for this route, I assume you have a separate function to handle the GET, right? If you don't, then your code won't work because there's no function to handle your redirect to the / which is a GET call

    UPDATES

    1. Your print statement won't show up by default because of the way Google App Engine handles logging.

      Switch to the logging module. Add the following to your code and then use logging.info("YO")

      import logging
      
      # Set the logging level
      logging.basicConfig(level=logging.INFO)
      
      
    2. If you want to get a 'close-enough' behavior of your App locally, then you should run it using dev_appserver.py. At the minimum, it will run your App with app.yaml and some (not all) of the restrictions that Google App Engine production has