The idea
In the last module you saw that a web server's whole job is: receive a request, send back a response. Flask is a small Python framework that handles the plumbing (reading requests, writing responses, speaking HTTP) so you only write the interesting part: what should happen when someone visits this URL?
Flask calls itself a micro-framework. It gives you routing, requests and responses, templates and little else. You add only what you need, which makes it a great framework for learning how the web really works, and for building small APIs and internal tools at work.
The smallest Flask app
Here's a complete web app in seven lines. When someone visits the home page of the site, it answers with a welcome message. Small as it is, every Flask app you'll ever build has these same parts:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def home():
return "Selamat datang di Toko Kita!"
Line by line:
from flask import Flaskimports theFlaskclass.app = Flask(__name__)creates your application.__name__tells Flask where your file lives, so it can find templates and static files later. Every Flask app starts with this line.@app.route("/")is a decorator: it registers the function below it as the handler for the URL path/, the home page.home()is a view function. Whatever it returns becomes the response body, here a plain string.
That's a complete web app. On this site, press Run, then open the Browser tab under the editor and press Send: it requests / from your app and shows the response.
Running it on your computer
Save the code as app.py, add Flask to your project with uv, and start the development server:
uv add flask
uv run flask --app app run --debug
Flask prints Running on http://127.0.0.1:5000. Open that address in your browser and you'll see your message. --debug turns on the reloader (the server restarts when you save the file) and shows detailed error pages. Use it while developing, never on a real public server.
This site can't open real network ports, so the Browser tab sends requests straight to your app object, using Flask's built-in test client. It's the same request and response a browser would get, without the network in between.
Routes: mapping URLs to functions
A route connects a URL path to a view function. Add as many as you like:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def home():
return "Selamat datang di Toko Kita!"
@app.route("/about")
def about():
return "Toko Kita sells coffee, kitchen gear and desk accessories."
@app.route("/contact")
def contact():
return "Email us at [email protected]"
Now /about and /contact work too. Request a path with no route, like /careers, and Flask returns 404 Not Found for you automatically.
A few rules of thumb:
- Paths start with
/and are case-sensitive:/Aboutis not/about. - Each view function needs a unique name. Two functions both called
homecause an error, because Flask uses function names to identify routes. - Name view functions after the page, not the action:
about,product_list,checkout.
Returning HTML
A view can return HTML as a string, and the browser renders it as a page:
@app.route("/")
def home():
return "<h1>Toko Kita</h1><p>Fresh coffee, delivered.</p>"
That's fine for a heading, but long HTML strings in Python get messy fast. In the templates module you'll move HTML into separate files, which is the clean way to do it. For now, short strings are perfect for learning.
What a response contains
When your view returns a string, Flask wraps it in a full HTTP response with three parts:
| Part | Example | Meaning |
|---|---|---|
| Status code | 200 OK | Did it work? 200 means success, 404 means not found. |
| Headers | Content-Type: text/html | Extra information, such as what kind of data the body is. |
| Body | Selamat datang di Toko Kita! | The actual content. |
You can return a different status code by adding it after the body, as a tuple:
@app.route("/old-shop")
def old_shop():
return "This page has moved to /", 410
410 Gone means "this existed once but was removed on purpose". You'll learn the important status codes in a later module.
Testing your app with the test client
Clicking around in a browser is slow and easy to forget. Flask has a test client that sends requests from Python and gives you the response to inspect. This is how professional Flask apps get tested, and it's also how the checks on this site work.
client = app.test_client()
response = client.get("/about")
print(response.status_code)
print(response.get_data(as_text=True))
200
Toko Kita sells coffee, kitchen gear and desk accessories.
client.get("/about")sends a GET request to/about.response.status_codeis the status number.response.get_data(as_text=True)gives the body as a string.
Why this matters for clean code
A route is a promise: "this URL does this one thing". Keep view functions small and focused. If a view starts doing five jobs (loading data, calculating, formatting, sending email), move those jobs into normal functions and call them from the view. Small views are easy to read, easy to test with the test client, and easy to change without breaking the rest of the site.
Recap
app = Flask(__name__)creates the app.@app.route("/path")maps a URL to a view function.- Whatever the view returns becomes the response body. Return
(body, status)to set a status code. - Unknown paths get 404 Not Found automatically.
- Start it locally with
flask --app app run --debug. app.test_client()sends requests from Python, the standard way to test Flask apps.