Learn
09.1 | FLASK SETUP, ROUTES AND RESPONSES
01 | THE BROWSER IS ONLY HALF THE STORY
A browser asks for a resource and displays the response. A static site can send an existing HTML file. A web application can instead run Python to decide what information to send, using a database, a signed-in user or submitted form data.
Flask is a Python web framework: reusable tools for handling requests and building responses. Your Python executes on the server, while the browser receives HTML, JSON or another representation. The browser does not run your Flask file as though it were JavaScript.
Imagine a reception desk. The address and request method describe what is being asked; a route directs the request to an appropriate handler; the handler prepares a response. The response can succeed or explain why the request could not be completed.
02 | PREPARE A PROJECT ENVIRONMENT
Create a project folder and a .venv using Topic 7. Install Flask through the selected interpreter. The range below is this course’s dependency policy, not a guarantee that every installation is identical.
Save source as route_demo.py, not flask.py, which could shadow the installed framework. Keep your terminal in the project folder so application discovery finds the intended module.
When installing into one environment and running another, a missing import is an interpreter-selection problem. Check sys.executable and python -m pip --version rather than changing the route code repeatedly.
TERMINAL | ACTIVATED PROJECT ENVIRONMENT
python -m pip install "Flask>=3.1,<4" python -m pip show Flask
03 | A COMPLETE FIRST ROUTE FILE
Flask(__name__) creates the application object and helps locate resources associated with the module. A decorator such as @app.get("/") registers the function below it as the handler for that URL path and GET method.
The function returns an HTML string, which Flask turns into a response. It is not printing into the browser: print writes to the server console, while return supplies the response content.
The project dictionary is fictional in-memory data. It resets when the process restarts and is not a substitute for stored records. The database lesson will replace this simple source.
from flask import Flask, abort
from markupsafe import escape
app = Flask(__name__)
projects = {1: "Robot controller", 2: "Study planner"}
@app.get("/")
def home():
return "<h1>My first Flask application</h1>"
@app.get("/hello/<name>")
def hello(name):
return f"<p>Hello, {escape(name)}!</p>"
@app.get("/projects/<int:project_id>")
def project(project_id):
if project_id not in projects:
abort(404)
return {"id": project_id, "title": projects[project_id]}
@app.get("/api/status")
def status():
return {"service": "learning", "ready": True}04 | START THE LOCAL DEVELOPMENT SERVER
With the file saved, run the command below and open http://127.0.0.1:5000/ in your browser. --app route_demo identifies the module containing the app. Ctrl+C in the terminal stops the process.
127.0.0.1 is the same computer; 5000 is the listening port. Another student’s browser using 127.0.0.1 reaches their own computer, not yours. If the port is occupied, use --port 5001 and match the browser URL.
The debug option reloads changed source and can provide an interactive debugger. Use it only for local development. The development server and debugger are unsuitable for public production hosting.
TERMINAL | WHERE ROUTE_DEMO.PY IS SAVED
python -m flask --app route_demo run --debug
05 | PATHS, PARAMETERS AND QUERY STRINGS
/projects/1 places an identifier in the path. The int converter supplies an integer project_id to the handler. The route then checks whether that ID exists; an integer-looking ID is not proof that a record is present or accessible.
/hello/Maya supplies text. escape(name) keeps characters such as < or > as displayed text instead of treating them as inserted HTML. Formatting untrusted text directly into HTML can create a cross-site scripting problem.
A query string supplies additional options after ?. For example, /projects?status=shared can provide a filter through request.args. Route arguments, query-string values and form values are different input locations, and all external values need deliberate rules.
06 | RETURN THE RIGHT KIND OF RESPONSE
An HTML response is suitable for a page. Returning a dictionary in Flask produces JSON, useful when another program consumes structured data. A status code communicates the result independently of the body’s wording.
200 normally means success, 404 means no matching resource, 405 means the method is not allowed, and 400 can report unsuitable submitted data. A page saying “not found” with a 200 status is a misleading protocol result.
A redirect sends the client to another URL. Later, a successful form POST returns a 303 redirect so the browser retrieves a result page with GET. Do not assume every request should return the same kind of content.
| Try this request | Expected result | Reason |
|---|---|---|
| GET / | 200 HTML | Home handler |
| GET /projects/1 | 200 JSON | Known project |
| GET /projects/999 | 404 | Unknown ID |
| GET /projects/text | 404 | No matching integer route |
| POST /api/status | 405 | GET-only route |
07 | GET RETRIEVES, POST REQUESTS A CHANGE
GET is intended to retrieve a representation, so following a link should not delete a project or sign somebody out. POST is commonly used for submitting a state-changing request. Method choices express the operation’s meaning.
Browsers, caches and crawlers may request GET URLs without the person intending a change. Putting deletion behind an ordinary GET link can therefore produce unwanted effects. The portal uses GET for a confirmation page and POST for the actual deletion.
POST is not encryption or authentication. It changes where form data is carried and what the request means; HTTPS, identity checks, access rules and form protection remain separate responsibilities.
08 | FOLLOW THE ROUTE MATCH
This fixed browser illustration selects a method and path from the first example. It shows routing outcomes without running Python or sending a request to your machine.
09 | CHECK A ROUTE WITHOUT OPENING A PORT
Flask’s test client invokes the application within a test process. It lets you inspect status, headers and content without starting a network server. Save the check below beside route_demo.py.
The test client is valuable for route logic, but it does not prove DNS, HTTPS certificates, reverse-proxy configuration or real browser usability. Those need their own checks.
response.json decodes a JSON reply for an assertion. It is different from reading server console print output: this is the content the client receives.
from route_demo import app
client = app.test_client()
print("Home:", client.get("/").status_code)
print("Project:", client.get("/projects/1").json["title"])
print("Missing:", client.get("/projects/999").status_code)EXPECTED OUTPUT
Home: 200 Project: Robot controller Missing: 404
10 | A SERVER NEEDS MORE THAN FILE UPLOAD
Uploading Flask source beside static HTML does not automatically run the Python server. Hosting must support the intended Python process, dependencies, application entry point and persistent storage.
Your existing Computer Science Café lesson pages remain ordinary HTML files. The downloaded student web apps are separate runnable projects. The deployment lesson explains that distinction rather than assuming a static hosting package can execute any Python file.
Try it: add a GET-only /about route, run it, then test an unknown path and an unsupported method. Explain the request, selected handler and returned response for each.
PUT YOUR SKILLS TO WORK
Use the Section 9 challenges to practise these ideas independently. Work in your Python editor, predict results and keep a short test record.
Section 9 challenges Python course navigation