Flask: Minimal Web Framework
Flask is a lightweight web framework for Python. It's "micro" โ it gives you the essentials without forcing a specific structure. Perfect for APIs, small web apps, and learning web development.
# Install Flask
# pip install flask
from flask import Flask, request, jsonify, render_template
app = Flask(__name__) # Create the app
# Routes map URLs to Python functions
@app.route("/")
def index():
return "Hello, World!"
@app.route("/hello/<name>") # URL parameter
def hello(name):
return f"Hello, {name}!"
@app.route("/about")
def about():
return "<h1>About Page</h1><p>Built with Flask</p>"
# Run the development server
if __name__ == "__main__":
app.run(debug=True, port=5000)# Start the server
python3 app.py
# * Running on http://127.0.0.1:5000
# * Debug mode: on (auto-reloads on file changes)HTTP Methods
@app.route("/items", methods=["GET", "POST"])
def items():
if request.method == "GET":
return jsonify({"items": ["apple", "banana"]})
elif request.method == "POST":
data = request.get_json() # Parse JSON body
name = data.get("name")
return jsonify({"created": name}), 201 # 201 = Created
@app.route("/items/<int:item_id>", methods=["GET", "PUT", "DELETE"])
def item(item_id):
if request.method == "GET":
return jsonify({"id": item_id, "name": "apple"})
elif request.method == "DELETE":
return jsonify({"deleted": item_id}), 200Request and Response
from flask import request, jsonify, make_response
@app.route("/search")
def search():
# Query parameters: /search?q=python&limit=10
query = request.args.get("q", "") # Default ""
limit = request.args.get("limit", 10, type=int)
return jsonify({"query": query, "limit": limit})
@app.route("/form", methods=["POST"])
def form():
# Form data
username = request.form.get("username")
return f"Hello, {username}"
@app.route("/upload", methods=["POST"])
def upload():
file = request.files.get("file")
if file:
file.save(f"uploads/{file.filename}")
return "Uploaded"
return "No file", 400
# Custom response headers
@app.route("/download")
def download():
response = make_response("file content")
response.headers["Content-Disposition"] = "attachment; filename=data.txt"
return responseTemplates with Jinja2
# templates/index.html
# <!DOCTYPE html>
# <html><head><title>{{ title }}</title></head>
# <body>
# <h1>{{ heading }}</h1>
# {% for item in items %}
# <li>{{ item }}</li>
# {% endfor %}
# </body></html>
@app.route("/page")
def page():
return render_template("index.html",
title="My Page",
heading="Welcome!",
items=["Python", "Flask", "Web Dev"]
)Error Handling and Configuration
from flask import abort
@app.route("/secret")
def secret():
if not current_user_is_admin():
abort(403) # Forbidden
return "Secret data"
# Custom error handlers
@app.errorhandler(404)
def not_found(e):
return jsonify({"error": "Not found"}), 404
@app.errorhandler(500)
def server_error(e):
return jsonify({"error": "Internal server error"}), 500
# Configuration
app.config["DEBUG"] = True
app.config["SECRET_KEY"] = "your-secret-key"
app.config["DATABASE_URL"] = "sqlite:///db.sqlite3"
# Better: load from environment
import os
app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY", "dev-key")
# App factory pattern (recommended for larger apps)
def create_app(config=None):
app = Flask(__name__)
if config:
app.config.from_object(config)
# Register blueprints, extensions, etc.
return appKey Takeaways
- @app.route() maps URLs to functions
- request object: access args, form, json, files
- jsonify() for APIs, render_template() for HTML
- debug=True: auto-reload and detailed error pages โ NEVER in production
- App factory pattern: create_app() function for testability and multiple configs
Practice Exercises
- Build a Flask app with a home page, an about page, and a /greet/<name> route.
- Build a simple in-memory to-do list API: GET /todos, POST /todos, DELETE /todos/<id>.
- Add a custom 404 error page to your app.
- Build a simple web form that accepts name+email and displays a confirmation page.