Customizing the Flask Response Class

Posted by
on under

The Flask response class, appropriately called Response, is rarely used directly by Flask applications. Instead, Flask uses it internally as a container for the response data returned by application route functions, plus some additional information needed to create an HTTP response.

What's not widely known, is that Flask gives applications the option to replace the stock response class with a custom one, opening the door to some neat tricks. In this article I'm going to show you how to take advantage of this technique to simplify your application code.

How Do Flask Responses Work?

Most applications do not use the Response class from Flask directly, but that does not mean it does not get used. In fact, Flask creates response objects for every request. So how does this work?

The response cycle begins when the function invoked by Flask to handle a request returns. In a web application, routes typically end with a call to the render_template function, which causes the referenced template file to be rendered and returned as a string:

@app.route('/index')
def index():
    # ...
    return render_template('index.html')

But as you probably know, a Flask route handler function can optionally return two additional values, which set a response status code and custom HTTP headers:

@app.route('/data')
def index():
    # ...
    return render_template('data.json'), 201, {'Content-Type': 'application/json'}

In this example, the status code is set to 201 to override the Flask 200 default, the standard code for a successfully handled request. The example also sets the Content-Type header to indicate that the response contains JSON data, because if you don't specifically set a content type, Flask sets it to HTML.

The above examples show the three basic components of a response, which are the data or body, the status code, and the headers. Flask's application instance has a make_response() function, which takes the return value from the route function (which can be a single value or a tuple with one, two or three values) and populates a Response object with them.

You can actually see how this process works in a Python console session. First create a virtual environment and install Flask in it, then start a Python session and type the following:

>>> from flask import Flask
>>> app = Flask(__name__)
>>> app.make_response('Hello, World')
<Response 12 bytes [200 OK]>
>>> app.make_response(('Hello, World', 201))
<Response 12 bytes [201 CREATED]>

Here I created a scratch Flask application instance, and then invoked the make_response() method to create some Response objects. In the first one I sent a string as argument, so the response is populated with defaults for status code and headers. In the second example I sent a tuple with two values, to force a non-default status code. Note the double parentheses in this second call, which wrap the string and the status code in a tuple. This is required because make_response() takes a single argument.

Once Flask has a Response object that represents the route function's response, it does a few things with it. Among them, it passes it to any defined after_request handlers, which gives the application a chance to insert or modify headers, change the body or the status code, or even replace the response with a completely new one if it so desires. In the end, Flask takes the final response object, renders it as HTTP, and sends it to the client.

The Flask Response Class

Let's look at the most interesting aspects of the response class. The following class definition shows what in my opinion are the salient attributes and methods of this class:

class Response:
    charset = 'utf-8'
    default_status = 200
    default_mimetype = 'text/html'

    def __init__(self, response=None, status=None, headers=None,
                 mimetype=None, content_type=None, direct_passthrough=False):
        pass

    @classmethod
    def force_type(cls, response, environ=None):
        pass

Note that if you go to the Flask source code you will not find the definitions above. Flask's Response class is actually a very tiny shell that derives from Werkzeug's class of the same name. In turn, Werzeug's Response class inherits from the BaseResponse class, in which the above elements are defined.

The three class attributes charset, default_status and default_mimetype define some defaults. If any of these defaults do not work for your application, then you can subclass the Response class and define your own, instead of having to set your custom values in every response. For example, if your application is an API that returns XML from all routes, you can change default_mimetype to application/xml in your custom response and then Flask will return XML responses by default, as you will see later.

I will not go into great detail describing the __init__ constructor (you can read about that in the Werkzeug documentation), but note that the three important elements of the Flask responses, which are the response body, the status code and the headers, are given as arguments. In a subclass, the constructor could change the rules that determine how responses are created.

The force_type() class method is the only non-trivial, yet very important, element of the response class. There are situations where Werkzeug or Flask need to create their own response objects, such as when an application error occurs and an error response needs to be given to the client. In this case the response object does not come from the application, it is the framework that creates it. In an application that uses a custom response class, Flask and Werkzeug can't possibly know the details of that custom class, so they create their responses using the standard response class. The force_type() method in a response class is supposed to take an instance of a different response class, and convert it to its own format.

I'm pretty sure you are confused by the description of force_type(). The bottom line is that whenever Flask comes across a response object that is not of the expected class, this method is used to convert it. The third use case that I'm going to show below takes advantage of this to allow Flask route functions to return objects such as dictionaries, lists or actually any custom object as a response to a request.

Well, that's enough theory. In the following section I'm going to show you how to put all these Response tricks into practice. Ready to get your hands dirty?

Using a Custom Response Class

By now I'm sure you agree that there are some interesting use cases that can benefit from using a custom response class. Before I show you some actual examples, let me tell you how simple it is to configure a Flask application to use a custom response class. Take a look at the following example:

from flask import Flask, Response

class MyResponse(Response):
    pass

app = Flask(__name__)
app.response_class = MyResponse

# ...

Here I have defined my custom response class with name MyResponse. Typically a custom response class adds or changes the behavior of the default response class, so it is common to create these custom classes as subclasses of Flask's Response class. To tell Flask to use my custom response class, all I need to do is set my class in app.response_class.

The response_class attribute of class Flask is a class attribute, so as a variant of the above example, you can create a subclass of Flask that has your response class set in it:

from flask import Flask, Response

class MyResponse(Response):
    pass

class MyFlask(Flask)
    response_class = MyResponse

app = MyFlask(__name__)

# ...

Example #1: Changing Response Defaults

The first example is extremely simple. Let's say your application returns XML in most or all endpoints. For such an application it would make sense to make application/xml the default content type. This is easily achieved with a two-line response class:

class MyResponse(Response):
    default_mimetype = 'application/xml'

Easy, right? If you set this class as the default response for the application, then you can write functions that return XML without worrying about setting the content type. For example:

@app.route('/data')
def get_data():
    return '''<?xml version="1.0" encoding="UTF-8"?>
<person>
    <name>John Smith</name>
</person>
'''

Using the default response, this route would receive the text/html content type, as that is the default. The custom response saves you from adding the additional header to all return statements in XML routes. And if you have some routes that need a different content type, you can still override the default, like you do with the regular response class:

@app.route('/')
def index():
    return '<h1>Hello, World!</h1>', {'Content-Type': 'text/html'}

Example #2: Determining Content Type Automatically

The next example is a little bit more involved. Let's say that this application has HTML and XML routes in equal amounts, so the first example does not really make sense, since regardless of which default you pick you would still have about half of the routes with an overriden content type.

A better solution would be to create a response class that can determine the correct content type by looking at the response text. The following class does that job:

class MyResponse(Response):
    def __init__(self, response, **kwargs):
        if 'mimetype' not in kwargs and 'contenttype' not in kwargs:
            if response.startswith('<?xml'):
                kwargs['mimetype'] = 'application/xml'
        return super(MyResponse, self).__init__(response, **kwargs)

In this example I first make sure the response does not specify an explicit content type. I then check if the text of the response begins with <?xml, indicating the data is formatted as an XML document. If both conditions are true, I insert the XML content type in the arguments I sent to the parent's class constructor.

With this response class, any properly formatted XML document will automatically receive the XML content type, while other responses will continue to receive the default content type. And in all cases I'm still free to explicitly provide the content type when necessary.

Example #3: Automatic JSON Responses

The final example deals with a common nuisance in Flask based APIs. It is very common for APIs to return JSON payloads, which requires you to use the jsonify() function to convert a Python dictionary to its JSON representation, and also to set the JSON content type in the response. Here is an example route that does this:

@app.route('/data')
def get_data():
    return jsonify({'foo': 'bar'})

Unfortunately every route that returns JSON needs to do this, so for a large API you end up repeating the jsonify() call a lot. From a code readability point of view, wouldn't it be nice if you could do this instead?

@app.route('/data')
def get_data():
    return {'foo': 'bar'}

Here is a custom response class that supports the above syntax, without affecting how other routes that do not return JSON work in any way:

class MyResponse(Response):
    @classmethod
    def force_type(cls, rv, environ=None):
        if isinstance(rv, dict):
            rv = jsonify(rv)
        return super(MyResponse, cls).force_type(rv, environ)

This example requires a bit of explanation. Flask recognizes just a handful of types as valid things that can be returned from a route handler function as a response body. Basically you can return any of the string and binary related types (str, unicode, bytes, bytearray), or if you prefer, you can return an already built response object. If you return any of the string or bytes types, Flask is going to realize that these are types that the response class knows how to handle, so it will pass what you return directly into the constructor of the response class.

But what happens when you return something unsupported, such as the dictionary of the example above? If the type of the returned response is not one of the expected ones, then Flask is going to assume that it is an unknown response object, so it will not try to create a response object passing it as an argument. Instead, it will use the force_type() class method on the response class to force a conversion from the unknown type. In this example the response subclass overrides this method and applies a conversion when a dictionary is given as a response. The conversion is done with a call jsonify(), before letting the base class take over as if nothing happened.

It's a neat trick, right? Consider that this does not affect the normal functioning of other responses. For any routes that return the normal response types the subclass does not do anything, all calls are passed transparently to the parent class.

Conclusion

I hope this article sheds some light on how responses work in Flask. If you know of other tricks you can do with Flask responses I would love to hear them!

Become a Patron!

Hello, and thank you for visiting my blog! If you enjoyed this article, please consider supporting my work on this blog on Patreon!

20 comments
  • #1 Leo said

    I am not able to customize the content type header, my code

    https://gist.github.com/Leo-G/ea2b0f534c53c3aa9e23

  • #2 Miguel Grinberg said

    @Leo: you posted an incomplete example, can't really tell you what's wrong.

  • #3 Alexander Simoes said

    Great article! Love any excuse to look under the Flask hood. Here's an example performing a similar function using a decorator instead of subclassing the Response object: http://justindonato.com/notebook/template-or-json-decorator-for-flask.html. One nice difference about this snippet is that it allows the response to be either HTML or JSON depending on whether the client requested it as XHR or not. A common use case of needing the same code in your view to execute if requested as XHR or on page load (esp for SEO purposes) and thus reduces code duplication.

  • #4 小穆 said

    I learned a lot of knowledge from your blog, thank you!

  • #5 Bs said

    Great blog! I hope you write a new book for learning advanced topic with Flask.

  • #6 Danel Segarra said

    Hi Miguel, I dont know any other way to reach you. Anyways, I am following your book which I got a few years ago, the Gmail confirmation does not work because Gmail keeps rejecting it. Any workaround? I tried other account as well with no luck. Thanks

  • #7 Miguel Grinberg said

    @Danel: Gmail introduced a security feature a while ago, which disables SMTP access by third party apps by default. You need to go into the gmail settings and enable this.

  • #8 Niraj Khandekar said

    Great article!

  • #9 Nikhil said

    Great article, great blog! Thank you for sharing so much. Is there a way to write out the request object in Flask? This is from the webapp2 framework: self.response.out.write(self.request) what is the Flask equivalent? Thanks in advance.

  • #10 Miguel Grinberg said

    @Nikhil: You can output the WSGI environment, which is used to construct the request object. This can be accessed as a dictionary with request.environ.

  • #11 Brian Williams said

    Miguel,

    I've found many of your blog posts and books very helpful in recent work projects. I realize this post is a couple of years old, but I didn't find much out there regarding using a custom response class on a specific blueprint. Is this possible?

    We have a single application that serves html content via one blueprint, and the primary purpose - an API serving JSON on another blueprint. I'd like to be able to force_type responses on the API blueprint to JSON type, and also make them be in a standard format via the custom response class.

    Can this be accomplished with still serving html responses/errors on the other blueprint?

  • #12 Miguel Grinberg said

    @Brian: haven't tried this, but in your force_type() method you can use request.blueprint to determine which blueprint you are on. That could allow you to implement different defaults for each of your blueprints.

  • #13 jlandercy said

    Thank you for sharing this article. Really useful. I would like to also force str to be converted into dict and then JSON. I mean something like this:

    class MyResponse(Response):
    @classmethod
    def force_type(cls, rv, environ=None):

        if isinstance(rv, str):
             return super(MyResponse, cls).force_type({"message": rv}, environ)
    
        if isinstance(rv, dict):
            rv = jsonify(rv)
        return super(MyResponse, cls).force_type(rv, environ)
    

    But returning a string from a view does not trigger force_type class method. Do you know how this could be achieved?

  • #14 Miguel Grinberg said

    @jlandercy: You can override the class constructor, which gets the original response. See http://flask.pocoo.org/docs/1.0/api/#flask.Response,

  • #15 Mohammad Saber said

    Thank you very much for your great article.
    My question is that how we can get two responses from flask application.

    I am writing a Flask application. This app captures video from webcam, calculates emotion metrics, and shows emotion metrics in the form of a real-time graph as well as face detected by webcam.

    The problem is that I cannot show both frames captured by webcam and real-time graph. My code only shows one of them. In app.py code, I return two generator functions by Response.

  • #16 Miguel Grinberg said

    @Mohammad: you can't return two responses. Make a single image by combining the two frames that you have and return a single response with it.

  • #17 Yasmin Amran said

    Hello Miguel
    Thankyou for the explenation.
    I followed all your flask mega-tutorial and created my own project based on it.
    It all worked well locally. However, there is a process that gets 30 seconds timeout on Heroku

    "2020-05-01T17:09:57.122232+00:00 heroku[router]: at=error code=H12 desc="Request timeout" method=GET path="/edit_student_destinations" host=yasmin-menta-matya-pt.herokuapp.com. ...

    Can you give an example of how to use
    return Response(generate(), mimetype='text/html')
    in flask project such as the one you showed on your mega-tutorial, to get around this timeout error on Heorku.
    Again, I think your mega-tutorial is the best on the internet. and I appreciate it very much.
    Regards Yasmin Amran

  • #18 Miguel Grinberg said

    @Yasmin: The H12 error means that your route did not start writing a response during the first 30 seconds. This cannot be changed, I believe, your route has to start the response within that time. See https://devcenter.heroku.com/articles/limits#http-timeouts for the details of how this works.

  • #19 Naman Churiwala said

    Hi Miguel, I had a small doubt regarding returning images as part of my response JSON in flask. Upon receiving a request, I fetch all the data that the user is asking for in that request from a DB and make a dictionary object out of it. Then I proceed to simply return the dictionary object. The issue is, one of the data fields I return is an image(which is stored in the DB as a Large binary). So my response dictionary looks something like:
    response = {'key1':val1, 'key2':val2....., 'image':image}
    I have tried to keep the value of the image key as the image's base64 encoding or keep it as a bytes object but everytime I get an error like: TypeError: Object of type bytes is not JSON serializable
    Can you help me provide a solution for this? Thank you!

  • #20 Miguel Grinberg said

    @Naman: convert your image data to base64, and then decode it to utf-8 so that it becomes a string. That will make it compatible with JSON.

Leave a Comment