Flask HTTP Methods
When building web applications with Flask, understanding HTTP methods is crucial for creating interactive and functional websites. HTTP methods define the types of actions that can be performed on resources and how clients (like browsers) communicate with your server.
Introduction to HTTP Methods
HTTP (Hypertext Transfer Protocol) defines several request methods that indicate the desired action to be performed on a resource. In Flask, you can specify which HTTP methods your route functions should respond to, allowing you to build RESTful APIs and process form submissions.
The most commonly used HTTP methods are:
- GET: Requests data from a specified resource
- POST: Submits data to be processed by a resource
- PUT: Updates a specified resource
- DELETE: Deletes a specified resource
- PATCH: Partially updates a resource
- HEAD: Same as GET but without the response body
- OPTIONS: Returns the supported HTTP methods for a URL
Handling HTTP Methods in Flask
In Flask, the default HTTP method for routes is GET. To specify which methods your route should handle, you can use the methods
parameter in the route decorator.
Basic Example: GET Method
Here's a basic example of a route that handles only GET requests:
from flask import Flask
app = Flask(__name__)
@app.route('/hello')
def hello():
return 'Hello, World!'
if __name__ == '__main__':
app.run(debug=True)
Since no methods are specified, this route only responds to GET requests.
Handling Multiple HTTP Methods
To handle multiple HTTP methods in a single route, you can specify them in a list:
from flask import Flask, request
app = Flask(__name__)
@app.route('/user', methods=['GET', 'POST'])
def user():
if request.method == 'POST':
return 'Creating a new user'
else: # GET request
return 'Getting user information'
if __name__ == '__main__':
app.run(debug=True)
In this example:
- If you send a GET request to
/user
, it returns "Getting user information" - If you send a POST request to
/user
, it returns "Creating a new user"
Accessing Request Data
Depending on the HTTP method, you'll need to access the request data differently.
Form Data (POST)
When handling form submissions with POST requests, you can access form data using request.form
:
from flask import Flask, request, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('form.html')
@app.route('/submit', methods=['POST'])
def submit():
name = request.form.get('name')
email = request.form.get('email')
return f'Form submitted! Name: {name}, Email: {email}'
if __name__ == '__main__':
app.run(debug=True)
A corresponding HTML form might look like:
<!-- templates/form.html -->
<!DOCTYPE html>
<html>
<head>
<title>Form Example</title>
</head>
<body>
<form action="/submit" method="post">
<div>
<label>Name:</label>
<input type="text" name="name">
</div>
<div>
<label>Email:</label>
<input type="email" name="email">
</div>
<button type="submit">Submit</button>
</form>
</body>
</html>
URL Query Parameters (GET)
For GET requests with URL parameters, you can access them using request.args
:
from flask import Flask, request
app = Flask(__name__)
@app.route('/search')
def search():
query = request.args.get('q', '')
return f'Searching for: {query}'
if __name__ == '__main__':
app.run(debug=True)
This route can be accessed with a URL like: http://localhost:5000/search?q=flask
JSON Data
For API requests that send JSON data, you can access it using request.json
:
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/api/data', methods=['POST'])
def process_json():
if not request.is_json:
return jsonify({"error": "Request must be JSON"}), 400
data = request.json
name = data.get('name', '')
return jsonify({"message": f"Hello, {name}!"})
if __name__ == '__main__':
app.run(debug=True)
You could test this with a tool like curl:
curl -X POST -H "Content-Type: application/json" -d '{"name":"John"}' http://localhost:5000/api/data
Building a RESTful API with Flask
A common use case for HTTP methods is building RESTful APIs. Here's an example of a simple API with different HTTP methods:
from flask import Flask, jsonify, request
app = Flask(__name__)
# Sample data
books = [
{"id": 1, "title": "Flask Web Development", "author": "Miguel Grinberg"},
{"id": 2, "title": "Python Crash Course", "author": "Eric Matthes"}
]
# GET all books
@app.route('/api/books', methods=['GET'])
def get_books():
return jsonify({"books": books})
# GET a specific book
@app.route('/api/books/<int:book_id>', methods=['GET'])
def get_book(book_id):
book = next((book for book in books if book["id"] == book_id), None)
if book:
return jsonify({"book": book})
return jsonify({"error": "Book not found"}), 404
# POST a new book
@app.route('/api/books', methods=['POST'])
def add_book():
if not request.json or 'title' not in request.json or 'author' not in request.json:
return jsonify({"error": "Invalid book data"}), 400
new_book = {
"id": books[-1]["id"] + 1 if books else 1,
"title": request.json["title"],
"author": request.json["author"]
}
books.append(new_book)
return jsonify({"book": new_book}), 201
# PUT (update) a book
@app.route('/api/books/<int:book_id>', methods=['PUT'])
def update_book(book_id):
book = next((book for book in books if book["id"] == book_id), None)
if not book:
return jsonify({"error": "Book not found"}), 404
if not request.json:
return jsonify({"error": "No data provided"}), 400
book["title"] = request.json.get("title", book["title"])
book["author"] = request.json.get("author", book["author"])
return jsonify({"book": book})
# DELETE a book
@app.route('/api/books/<int:book_id>', methods=['DELETE'])
def delete_book(book_id):
global books
book = next((book for book in books if book["id"] == book_id), None)
if not book:
return jsonify({"error": "Book not found"}), 404
books = [book for book in books if book["id"] != book_id]
return jsonify({"result": True})
if __name__ == '__main__':
app.run(debug=True)
This is a complete RESTful API that allows you to:
- GET all books or a specific book
- POST a new book
- PUT (update) an existing book
- DELETE a book
Method Override
Some browsers or HTML forms only support GET and POST methods. To use other methods like PUT or DELETE from an HTML form, you can use method override. A common approach is to use a hidden form field or a query parameter named _method
.
Here's how you could implement a simple method override in Flask:
from flask import Flask, request
app = Flask(__name__)
@app.before_request
def handle_method_override():
if request.method == 'POST':
method = request.form.get('_method', '').upper()
if method in ['PUT', 'DELETE', 'PATCH']:
request.environ['REQUEST_METHOD'] = method
# Your routes here...
if __name__ == '__main__':
app.run(debug=True)
Safe and Idempotent Methods
It's important to understand some characteristics of HTTP methods:
- Safe methods: These don't change the server's state (GET, HEAD, OPTIONS)
- Idempotent methods: Multiple identical requests have the same effect as a single request (GET, PUT, DELETE, HEAD, OPTIONS)
Understanding these properties helps you design better APIs and web applications.
Practical Example: Login Form
Here's a practical example of a login form using Flask HTTP methods:
from flask import Flask, request, render_template, redirect, url_for, session
app = Flask(__name__)
app.secret_key = 'your_secret_key' # Required for sessions
# Simple user database
users = {
'user1': 'password1',
'user2': 'password2'
}
@app.route('/')
def home():
if 'username' in session:
return f'Logged in as {session["username"]}. <a href="/logout">Logout</a>'
return redirect(url_for('login'))
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
if username in users and users[username] == password:
session['username'] = username
return redirect(url_for('home'))
return render_template('login.html', error='Invalid username or password')
return render_template('login.html')
@app.route('/logout')
def logout():
session.pop('username', None)
return redirect(url_for('login'))
if __name__ == '__main__':
app.run(debug=True)
And the corresponding login template:
<!-- templates/login.html -->
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
</head>
<body>
<h2>Login</h2>
{% if error %}
<p style="color: red;">{{ error }}</p>
{% endif %}
<form method="post">
<div>
<label>Username:</label>
<input type="text" name="username" required>
</div>
<div>
<label>Password:</label>
<input type="password" name="password" required>
</div>
<button type="submit">Login</button>
</form>
</body>
</html>
Summary
HTTP methods are essential for building interactive web applications with Flask. They allow you to:
- Handle different types of requests with the same route
- Create RESTful APIs with clear semantics
- Process form submissions and API requests
- Build secure and maintainable web applications
Understanding when to use each HTTP method is crucial for designing web applications that follow best practices and provide a good user experience.
Additional Resources
Exercises
-
Create a simple to-do list application that can:
- Display all tasks (GET)
- Add new tasks (POST)
- Mark tasks as completed (PUT)
- Delete tasks (DELETE)
-
Build a user registration form that validates the input and stores user information.
-
Create a RESTful API for managing blog posts, including routes for creating, reading, updating, and deleting posts.
-
Implement a file upload feature using Flask's request.files to handle file uploads via POST requests.
-
Add method override functionality to an HTML form to allow PUT and DELETE requests.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)