HTTP Methods (GET & POST)
Reviewed & published by Brayan K
An HTTP method is the type of action a request performs: GET asks the server for something (a page or data), while POST sends data to the server, such as a submitted form.
Part of the free Flask course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
In this lesson you'll let routes accept POST, read submitted form data with request.form, and handle GET and POST in one view function. Try each app locally with flask run.
What You'll Learn in This Lesson
- The difference between GET and POST
- How to allow methods with methods=['GET','POST']
- Reading form data with request.form
- Checking request.method inside a view
- Reading query strings with request.args
- Handling a form submission end to end
1 GET vs POST
Every request a browser makes has an HTTP method. The two you'll use most are:
- GET — "give me this resource." Used for normal page visits and links. Carries no body; any data rides in the URL.
- POST — "here is some data to process." Used for submitting forms. The data travels in the request body, not the URL.
By default, a Flask route only answers GET. To accept POST you list it in the decorator with methods=["GET", "POST"]. The app below allows both and reports which method was used by reading request.method.
# methods.py — a route that accepts GET and POST
from flask import Flask, request
app = Flask(__name__)
# Without methods=[...] this route would only allow GET.
@app.route("/submit", methods=["GET", "POST"])
def submit():
if request.method == "POST":
return "<h1>You sent data with POST</h1>"
return "<h1>You loaded the page with GET</h1>"
# Inspect which methods each rule allows:
for rule in app.url_map.iter_rules():
print(rule.rule, "->", sorted(rule.methods - {"HEAD", "OPTIONS"}))
# Run locally with: flask run
# ✅ Expected output:
# /static/<path:filename> -> ['GET']
# /submit -> ['GET', 'POST']2 Reading Form Data with request.form
When a form is submitted with POST, the values land in request.form, which works like a dictionary keyed by each input's name. Use request.form.get("field") to read a value safely — it returns None instead of crashing if the field is missing.
The app below shows a login-style form on GET and greets the user on POST after reading the username field they typed.
# Show a form, then read the submitted value
from flask import Flask, request
app = Flask(__name__)
@app.route("/greet", methods=["GET", "POST"])
def greet():
if request.method == "POST":
# .get() returns None if the field wasn't sent
name = request.form.get("username", "stranger")
return f"<h1>Hello, {name}!</h1>"
# On GET, return an HTML form that POSTs back to /greet
return """
<form method="POST">
<input name="username" placeholder="Your name">
<button type="submit">Greet me</button>
</form>
"""
# Simulate reading a value the way Flask would:
fake_form = {"username": "Ada"}
print("Would greet:", fake_form.get("username", "stranger"))
# ✅ Expected output:
# Would greet: AdaThe form's method="POST" attribute is what sends the data in the body. Each input's name becomes the key you read from request.form.
3 Query Strings with request.args
GET requests can still carry data — in the query string, the part of a URL after the ?. Flask exposes those values in request.args. For example, a search box might link to /search?q=flask.
# Reading query string values from a GET request
from flask import Flask, request
app = Flask(__name__)
# Visiting /search?q=flask -> request.args["q"] == "flask"
@app.route("/search")
def search():
term = request.args.get("q", "")
if not term:
return "<h1>Type a search term, e.g. /search?q=flask</h1>"
return f"<h1>Results for: {term}</h1>"
# Simulate the query string Flask would parse:
fake_args = {"q": "flask"}
print("Searching for:", fake_args.get("q", ""))
# Run locally: flask run, then open /search?q=flask
# ✅ Expected output:
# Searching for: flask🔬 GET vs POST at a Glance
| Aspect | GET | POST |
|---|---|---|
| Purpose | Fetch a page or data | Send data to process |
| Where data lives | URL query string | Request body |
| Read it with | request.args | request.form |
| Default in Flask | Allowed | Must opt in |
🎯 Your Turn: Fill in the Blanks
Finish a route that accepts a POST and reads an email field. Replace each ___.
# 🎯 YOUR TURN: replace each ___ to handle a POST
from flask import Flask, ___ # what do we import to read forms?
app = Flask(__name__)
@app.route("/signup", methods=["GET", "___"]) # allow form submission
def signup():
if request.method == "___": # only on submit
email = request.___.get("email", "") # read the form field
return f"<h1>Signed up: {email}</h1>"
return '<form method="POST"><input name="email"><button>Go</button></form>'
print("signup route ready")Common Errors & Quick Reference
❌ 405 Method Not Allowed
You submitted a POST to a route that only allows GET. Add methods=["GET", "POST"] to the @app.route decorator.
❌ 400 Bad Request from request.form["x"]
The field wasn't in the submission, so the dictionary lookup failed. Use request.form.get("x") instead, which returns None rather than raising.
| Task | Code |
|---|---|
| Allow POST | methods=["GET", "POST"] |
| Check the method | request.method == "POST" |
| Read a form field | request.form.get("name") |
| Read a query value | request.args.get("q") |
🏆 Mini Challenge: A Feedback Form
Build a single route that shows a feedback form and processes it.
- Allow both GET and POST on /feedback
- On GET, return a form with a message field
- On POST, read request.form and thank the user, echoing their message
# 🏆 Mini Challenge: a feedback form
from flask import Flask, request
app = Flask(__name__)
@app.route("/feedback", methods=["GET", "POST"])
def feedback():
if request.method == "POST":
message = request.form.get("message", "")
return f"<h1>Thanks!</h1><p>You said: {message}</p>"
return """
<form method="POST">
<textarea name="message" placeholder="Your feedback"></textarea>
<button type="submit">Send</button>
</form>
"""
# Simulate a submission
fake = {"message": "Great course!"}
print("Received:", fake.get("message", ""))❓ Frequently Asked Questions
Lesson complete — your app can receive data!
You now know the difference between GET and POST, how to allow methods on a route, and how to read user input from request.form and request.args. That's the foundation of every interactive web app.
Practice quiz
What is the GET method used for?
- Deleting a resource
- Asking the server for a resource
- Encrypting data
- Restarting the server
Answer: Asking the server for a resource. GET asks the server for something, like a page or data.
Where does data travel in a POST request?
- In the URL path
- In the response
- In the request body
- In a cookie
Answer: In the request body. POST sends data in the request body, not the URL.
By default, which method does a Flask route accept?
- POST only
- Both GET and POST
- PUT only
- GET only
Answer: GET only. A route answers only GET unless you list other methods.
How do you allow POST on a route?
- methods=["GET", "POST"] in @app.route
- post=True
- @app.post_only
- allow_post()
Answer: methods=["GET", "POST"] in @app.route. Add methods=["GET", "POST"] to the @app.route decorator.
Where do submitted POST form values appear?
- request.args
- request.form
- request.cookies
- request.path
Answer: request.form. Posted form fields are read from request.form.
How do you check which method a request used?
- request.verb
- request.type
- request.method
- request.kind
Answer: request.method. request.method holds the HTTP method string, e.g. "POST".
Where do query-string values (after ?) appear?
- request.form
- request.body
- request.cookies
- request.args
Answer: request.args. Query string values are exposed in request.args.
Why prefer request.form.get("x") over request.form["x"]?
- It returns None instead of raising when the field is missing
- It is faster
- It validates the value
- It logs the request
Answer: It returns None instead of raising when the field is missing. .get() avoids a 400/KeyError when a field wasn't submitted.
What HTTP error means you POSTed to a GET-only route?
- 404 Not Found
- 405 Method Not Allowed
- 500 Internal Error
- 302 Found
Answer: 405 Method Not Allowed. 405 Method Not Allowed means the verb isn't permitted on that route.
For a search box linking to /search?q=flask, how do you read q?
- request.form.get("q")
- request.path
- request.json["q"]
- request.args.get("q")
Answer: request.args.get("q"). Query parameters are read from request.args.
Continue this course
- Previous: Dynamic Routes & Variables
- Next: Templates with Jinja2 — Render HTML pages with the Jinja2 templating engine
- Quick reference: Flask cheat sheet › Setup & Routes
Frequently asked questions
What is an HTTP method?
An HTTP method is the kind of action a request wants to perform. GET asks the server for a page or data, while POST sends data to the server, such as a submitted form. They tell your route what the client is trying to do.
How do I allow POST on a Flask route?
Pass a methods list to the decorator: @app.route('/submit', methods=['GET', 'POST']). By default a route only accepts GET, so you must explicitly opt in to POST.
How do I read submitted form data?
Import request from flask and read request.form, which behaves like a dictionary. request.form['name'] or request.form.get('name') gives you the value the user typed into a field named 'name'.
What is the difference between request.form and request.args?
request.form holds data sent in the body of a POST request (typically a form). request.args holds values from the query string of the URL, like the part after the ? in a GET request.