What is Flask?
Flask is a lightweight WSGI web framework in Python. It is designed to be simple and easy to extend, giving you the flexibility to structure your application however you want. Flask is often called a "micro-framework" because it does not include an ORM, form validation, or other features that many frameworks provide by default. Instead, you choose and add extensions as needed.
Hello World
# Install Flask
# pip install flask
# app.py
from flask import Flask, jsonify, request, render_template
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello, World!"
@app.route("/api/greeting")
def api_greeting():
name = request.args.get("name", "World")
return jsonify({"message": f"Hello, {name}!"})
if __name__ == "__main__":
app.run(debug=True)
# Run: python app.py
# Or: flask --app app run --debug
Routing and HTTP Methods
from flask import Flask, jsonify, request, abort
app = Flask(__name__)
# In-memory storage for demo
todos = [
{"id": 1, "title": "Learn Flask", "done": False},
{"id": 2, "title": "Build API", "done": False},
]
next_id = 3
# GET all todos
@app.route("/api/todos", methods=["GET"])
def get_todos():
return jsonify(todos)
# GET single todo
@app.route("/api/todos/", methods=["GET"])
def get_todo(todo_id):
todo = next((t for t in todos if t["id"] == todo_id), None)
if not todo:
abort(404)
return jsonify(todo)
# POST create todo
@app.route("/api/todos", methods=["POST"])
def create_todo():
global next_id
if not request.json or "title" not in request.json:
abort(400)
todo = {
"id": next_id,
"title": request.json["title"],
"done": False,
}
next_id += 1
todos.append(todo)
return jsonify(todo), 201
# PUT update todo
@app.route("/api/todos/", methods=["PUT"])
def update_todo(todo_id):
todo = next((t for t in todos if t["id"] == todo_id), None)
if not todo:
abort(404)
data = request.json
todo["title"] = data.get("title", todo["title"])
todo["done"] = data.get("done", todo["done"])
return jsonify(todo)
# DELETE todo
@app.route("/api/todos/", methods=["DELETE"])
def delete_todo(todo_id):
global todos
todos = [t for t in todos if t["id"] != todo_id]
return "", 204
Blueprints for Organization
# Blueprints help organize large Flask applications
# auth/routes.py
from flask import Blueprint, jsonify, request
auth_bp = Blueprint("auth", __name__, url_prefix="/auth")
@auth_bp.route("/login", methods=["POST"])
def login():
data = request.json
# Authenticate user...
return jsonify({"token": "jwt-token-here"})
@auth_bp.route("/register", methods=["POST"])
def register():
data = request.json
# Create user...
return jsonify({"message": "User created"}), 201
# products/routes.py
from flask import Blueprint, jsonify
products_bp = Blueprint("products", __name__, url_prefix="/products")
@products_bp.route("/")
def list_products():
return jsonify([{"id": 1, "name": "Widget"}])
# app.py - register blueprints
from flask import Flask
# from auth.routes import auth_bp
# from products.routes import products_bp
app = Flask(__name__)
# app.register_blueprint(auth_bp)
# app.register_blueprint(products_bp)
Error Handling and Middleware
from flask import Flask, jsonify
from werkzeug.exceptions import HTTPException
app = Flask(__name__)
# Custom error handlers
@app.errorhandler(404)
def not_found(error):
return jsonify({"error": "Resource not found"}), 404
@app.errorhandler(400)
def bad_request(error):
return jsonify({"error": "Bad request"}), 400
@app.errorhandler(500)
def internal_error(error):
return jsonify({"error": "Internal server error"}), 500
# Catch all HTTP exceptions
@app.errorhandler(HTTPException)
def handle_exception(e):
return jsonify({"error": e.description, "code": e.code}), e.code
# Before/after request hooks (middleware)
@app.before_request
def log_request():
print(f"{request.method} {request.path}")
@app.after_request
def add_cors_headers(response):
response.headers["Access-Control-Allow-Origin"] = "*"
response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE"
return response
# Configuration
app.config["SECRET_KEY"] = "your-secret-key"
app.config["DEBUG"] = True
# Or from a config file/object
class Config:
SECRET_KEY = "your-secret-key"
SQLALCHEMY_DATABASE_URI = "sqlite:///app.db"
app.config.from_object(Config)
Flask vs Django vs FastAPI
- Flask: Maximum flexibility, minimal opinions, great for small-medium APIs and apps
- Django: Batteries-included, great for full-stack web apps with admin panels
- FastAPI: Best for modern REST APIs, async support, automatic validation and docs