Flask Cheatsheet

Responses

Use this Flask reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Return Values from Views

Flask accepts several return types from view functions. All are converted to a Response object.

# 1. String → 200 text/html
return "Hello"

# 2. (body, status)
return "Not Found", 404

# 3. (body, headers)
return "OK", {"X-Custom": "value"}

# 4. (body, status, headers)
return "Created", 201, {"Location": "/items/1"}

# 5. Response object
from flask import Response
return Response("OK", status=200, mimetype="text/plain")

# 6. dict or list → auto-JSON (Flask 2.2+)
return {"id": 1, "name": "Alice"}      # 200 application/json
return [{"id": 1}, {"id": 2}]          # 200 application/json

# 7. jsonify
from flask import jsonify
return jsonify({"id": 1})

make_response

Use when you need to set cookies, headers, or status on a template response:

from flask import make_response, render_template

@app.route("/cookie-demo")
def cookie_demo():
    resp = make_response(render_template("index.html"))
    resp.set_cookie("theme", "dark")
    resp.headers["X-Frame-Options"] = "DENY"
    resp.status_code = 200
    return resp

make_response accepts the same tuple forms:

resp = make_response("body", 201)
resp = make_response(("body", 201, {"X-Foo": "bar"}))

Response Object Attributes and Methods

Attribute / MethodDescription
resp.status_codeInteger HTTP status
resp.statusString status e.g. "200 OK"
resp.dataBody as bytes
resp.get_data(as_text=True)Body as string
resp.mimetypeMIME type without params
resp.content_typeFull Content-Type header
resp.headersHeaders object (mutable)
resp.headers["X-Key"] = "v"Set a header
resp.headers.add("Vary", "Accept")Append header
resp.set_cookie(...)Set a cookie (see Cookies)
resp.delete_cookie(key)Expire a cookie
resp.autocorrect_location_headerAuto-fix Location URLs (deprecated)
resp.direct_passthroughStream without reading (use with send_file)

Redirects

from flask import redirect, url_for

@app.route("/old")
def old():
    return redirect(url_for("new"))           # 302 Found

@app.route("/moved")
def moved():
    return redirect("/new-path", code=301)    # 301 Moved Permanently

@app.route("/see-other")
def see_other():
    return redirect(url_for("index"), 303)    # 303 See Other (POST→GET)

Common redirect codes:

CodeNameUse case
301Moved PermanentlyURL changed forever; browsers cache
302FoundTemporary redirect (default)
303See OtherAfter POST; forces GET on redirect
307Temporary RedirectPreserves method (POST stays POST)
308Permanent RedirectPreserves method, cached

Abort (Error Responses)

from flask import abort

abort(404)                   # raises HTTPException immediately
abort(403)
abort(400, "Invalid input")  # description (shown in default error page)
abort(Response("custom body", 418))   # abort with a custom Response

abort() never returns — it raises and exits the view immediately.

JSON Responses

from flask import jsonify

@app.route("/api/user/<int:id>")
def get_user(id):
    user = {"id": id, "name": "Alice"}
    return jsonify(user), 200

# Lists
return jsonify([{"id": 1}, {"id": 2}])

# Nested
return jsonify({"users": [{"id": 1}], "total": 1})

jsonify sets Content-Type: application/json and serializes using json.dumps with Flask's encoder (handles datetime, UUID, Decimal via app.json).

Custom JSON encoder (Flask 2.2+):

from flask.json.provider import DefaultJSONProvider
import decimal

class CustomProvider(DefaultJSONProvider):
    def default(self, o):
        if isinstance(o, decimal.Decimal):
            return str(o)
        return super().default(o)

app.json_provider_class = CustomProvider
app.json = CustomProvider(app)

Streaming Responses

from flask import stream_with_context, Response

def generate():
    for i in range(100):
        yield f"data: {i}\n\n"

@app.route("/stream")
def stream():
    return Response(stream_with_context(generate()), mimetype="text/event-stream")

stream_with_context keeps the request context alive while the generator runs.

Large file streaming:

def read_file_chunks(path, chunk_size=8192):
    with open(path, "rb") as f:
        while chunk := f.read(chunk_size):
            yield chunk

@app.route("/download")
def download():
    return Response(read_file_chunks("/path/to/file"), mimetype="application/octet-stream")

Sending Files

from flask import send_file, send_from_directory

# Send a file object or path
send_file("path/to/report.pdf")
send_file("report.pdf", mimetype="application/pdf")
send_file("report.pdf", as_attachment=True)                # Content-Disposition: attachment
send_file("report.pdf", download_name="my-report.pdf")     # rename for download
send_file(io.BytesIO(data), mimetype="image/png")          # in-memory file

# Safe directory serving (prevents path traversal)
send_from_directory("uploads", filename)
send_from_directory(app.config["UPLOAD_FOLDER"], filename, as_attachment=True)

send_from_directory raises 404 if the file does not exist and rejects paths that escape the directory. Prefer it over send_file for user-supplied filenames.

Setting Cookies on Responses

resp = make_response("OK")
resp.set_cookie(
    "session_id",
    value="abc123",
    max_age=3600,            # seconds until expiry (alternative to expires)
    expires=None,            # datetime or timestamp
    path="/",
    domain=None,             # defaults to current domain
    secure=True,             # HTTPS only
    httponly=True,           # no JS access
    samesite="Lax",          # "Strict", "Lax", or "None"
)
resp.delete_cookie("old_cookie")

Response Headers

@app.after_request
def security_headers(resp):
    resp.headers["X-Content-Type-Options"] = "nosniff"
    resp.headers["X-Frame-Options"] = "SAMEORIGIN"
    resp.headers["Content-Security-Policy"] = "default-src 'self'"
    resp.headers["Strict-Transport-Security"] = "max-age=31536000"
    return resp

Caching Headers

from flask import Response

resp = make_response(render_template("page.html"))
resp.cache_control.max_age = 300        # 5 minutes
resp.cache_control.public = True
resp.cache_control.no_cache = True      # revalidate every time
resp.cache_control.no_store = True      # sensitive data — never cache
resp.headers["ETag"] = "abc123"
resp.headers["Last-Modified"] = "Wed, 21 Oct 2023 07:28:00 GMT"

CORS Headers (Manual)

@app.after_request
def cors(resp):
    resp.headers["Access-Control-Allow-Origin"] = "*"
    resp.headers["Access-Control-Allow-Headers"] = "Content-Type,Authorization"
    resp.headers["Access-Control-Allow-Methods"] = "GET,POST,PUT,DELETE,OPTIONS"
    return resp

@app.route("/api/<path:path>", methods=["OPTIONS"])
def options_handler(path):
    return "", 204

For production, use flask-cors:

pip install flask-cors
from flask_cors import CORS
CORS(app)
CORS(app, resources={r"/api/*": {"origins": "https://example.com"}})