Flask Cheatsheet

Responses

Use this Flask reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

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"}})