AdjunctProfessorFalcon
AdjunctProfessorFalcon

Reputation: 1840

Understanding 400 error during AJAX Post request to Flask endpoint

Trying to understand what I'm doing wrong here when using JQuery AJAX POST request to send both form data and an attached file to a Flask endpoint.

The basic Flask view that I'm still building looks like this:

@main.route('/videoupload', methods=['GET','POST'])
def videoupload():
    if request.method == 'POST':
        ajaxpost = request.form['m_data']
        print(ajaxpost)
    return render_template('videoupload.html')

The JQuery for the form and attached file looks like this:

$("#submit_btn").click(function() {  
        var proceed = true;

        if(proceed) //everything looks good! proceed...
        {
            //data to be sent to server
            var m_data = new FormData();    
            m_data.append( 'video_title', $('input[name=videoTitle]').val());
            m_data.append( 'video_description', $('input[name=videoDescription]').val());
            m_data.append( 'video_tags', $('input[name=videoTags]').val());
            m_data.append( 'file_attach', $('input[name=file_attach]')[0].files[0]);
            //instead of $.post() we are using $.ajax()
            //that's because $.ajax() has more options and flexibly.
            $.ajax({
              url: '/videoupload',
              data: m_data,
              processData: false,
              contentType: false,
              type: 'POST',
                  //dataType:'json',
              datatype:'json',
              success: function(response){
                 //load json data from server and output message     
                if(response.type == 'error'){ //load json data from server and output message     
                    output = '<div class="error">'+response.text+'</div>';
                }else{
                    output = '<div class="success">'+response.text+'</div>';
                }
                $("#videoform #form_results").hide().html(output).slideDown();
              }
            });        
        }
    });

Using Firebug and the Net window, I can confirm that data entered in the fields of the form and the attached file are being appended to the FormData() object.

When the user clicks Submit button, I get the following error in the Console:

> POST http://127.0.0.1:8000/videoupload 400 (BAD REQUEST)
send @ jquery.js:9664
m.extend.ajax @ jquery.js:9215
(anonymous function) @ videoupload:137
n.event.dispatch @ jquery.min.js:3
r.handle @ jquery.min.js:3

Navigated to http://127.0.0.1:8000/videoupload?videoTitle=asdf&videoDescription=asdfasdfasdfasdfasdf&videoTags=ZcZXcZXcZXcZXC&file_attach=ScreenCaptureProject1.mp4

In the Terminal window running Flask app (using Gunicorn) running in debug mode, no errors appear:

[2016-05-20 00:18:21 -0400] [27033] [DEBUG] POST /videoupload
POST CALLED
[2016-05-20 00:18:24 -0400] [27033] [DEBUG] GET /videoupload

It seems as though the AJAX is pinging the Flask view with a POST request. Am I handling the form incorrectly in the Flask view? Is there something incorrect with the JQuery AJAX POST request that Flask doesn't like?

Upvotes: 1

Views: 1616

Answers (1)

A. Vidor
A. Vidor

Reputation: 2550

request.form is a MultiDict with the key-value pairs of the received form data.

You are attempting to index this dictionary using the string 'm_data' as a key, but it looks like 'm_data' is just the name of your JavaScript variable and not actually a key of the form data. If 'm_data' is not a valid key this would raise an exception.

To quote the Werkzeug documentation on MultiDicts:

"From Werkzeug 0.3 onwards, the KeyError raised by this class is also a subclass of the BadRequest HTTP exception and will render a page for a 400 BAD REQUEST if caught in a catch-all for HTTP exceptions."

To help debug this route, you can wrap your python code in a try-except block:

@main.route('/videoupload', methods=['GET','POST'])
def videoupload():
    if request.method == 'POST':
        try:
            [your code]
        except Exception, e:
            print e
    return render_template('videoupload.html')

Then you can check whether a KeyError appears in the error logs (or console if you're running the Flask test server locally).

Upvotes: 1

Related Questions