Flask request and application/json content type

59,957

Solution 1

Use request.get_json() and set force to True:

@menus.route('/', methods=["PUT", "POST"])
def new():
    return jsonify(request.get_json(force=True))

From the documentation:

By default this function will only load the json data if the mimetype is application/json but this can be overridden by the force parameter.

Parameters:

  • force – if set to True the mimetype is ignored.

For older Flask versions, < 0.10, if you want to be forgiving and allow for JSON, always, you can do the decode yourself, explicitly:

from flask import json

@menus.route('/', methods=["PUT", "POST"])
def new():
    return jsonify(json.loads(request.data))

Solution 2

the request object already has a method get_json which can give you the json regardless of the content-type if you execute it with force=True so your code would be something like the following:

@menus.route('/', methods=["PUT", "POST"])
def new():
    return jsonify(request.get_json(force=True))

in fact, the flask documentation says that request.get_json should be used instead of request.json: http://flask.pocoo.org/docs/api/?highlight=json#flask.Request.json

Share:
59,957
danielrvt
Author by

danielrvt

Computer Engineer graduated from Universidad Simon Bolivar, currently living in Caracas, Venezuela. GIS, Mobile and Web app developer... Web is my favorite. Always thinking about user experience and passionate about Python and JavaScript (There is something sexy about dynamic languages...). I also love using GIT and developing Augmented Reality applications with ARToolkit. My account on GitHub is this: https://github.com/danielrvt. See you on SO!!!

Updated on March 02, 2020

Comments

  • danielrvt
    danielrvt about 4 years

    I have a flask app with the following view:

    @menus.route('/', methods=["PUT", "POST"])
    def new():
        return jsonify(request.json)
    

    However, this only works if the request's content type is set to application/json, otherwise the dict request.json is None.

    I know that request.data has the request body as a string, but I don't want to be parsing it to a dict everytime a client forgets to set the request's content-type.

    Is there a way to assume that every incoming request's content-type is application/json? All I want is to always have access to a valid request.json dict, even if the client forgets to set the application content-type to json.

  • danielrvt
    danielrvt over 11 years
    Thats what I ended up doing :)
  • Martijn Pieters
    Martijn Pieters almost 11 years
    @RonReiter: Why doesn't it? We take the request.data regardless of the content type specified by the client. Sure, if the client sent invalid request data (e.g. not (valid) JSON), nothing can be done.
  • Ron Reiter
    Ron Reiter almost 11 years
    @MartijnPieters request.data is an empty string when using www/form-url-encoded because it parses it as a form. From the documentation: data - Contains the incoming request data as string in case it came with a mimetype Flask does not handle.
  • Martijn Pieters
    Martijn Pieters almost 11 years
    Right, in narrow cases, where a client completely mislabeled the request, the above will fail. How likely is that case, and isn't that true for many other cases where a client malformed the request?
  • Tony Chou
    Tony Chou about 6 years
    Is it a bad idea or not recommended to make any coming data to json? I mean always use request.get_json(force=True) any where in back-end to extract data.
  • Martijn Pieters
    Martijn Pieters about 6 years
    @TonyChou: gating on the Content-Type header is one way of blocking bad clients early. If you use force=True just because some clients may have forgotten to set the header, then your server will have to do more work (because now all requests could contain JSON and time is spent trying to decode it all).
  • dinvlad
    dinvlad about 3 years
    This is actually a way to protect your app against CSRF attacks. If someone makes a POST to your app from another site, and your app uses auth cookies that are not SameSite, then these cookies will be automatically attached to the request, and without Content-Type: application/json header present, the request would be considered "simple" and thus submitted to the server. So this ends up making your app vulnerable to CSRF, unless you check Content-Type (this happens irregardless of if/how you set CORS headers btw, the POST request would still be submitted for a "simple" request).