The idea
Every time you open a web page, two programs have a short conversation. Your browser (the client) sends a request: "please give me /products". A server program receives it, decides what to send back, and replies with a response: "here's the page, status OK". That's the entire web, repeated billions of times a day.
A web framework like Flask is the code that handles the boring, error-prone parts of that conversation, so you only write the interesting part: given this request, what's the response?
A restaurant. The customer (browser) hands the waiter an order slip (request). The kitchen (your code) prepares the dish. The waiter brings back the plate with a note "all good" or "sorry, sold out" (response with a status). Flask is the waiter: it takes orders in a standard format, gets each one to the right cook, and delivers the result properly.
The request
When you visit https://tokokita.id/products?category=Coffee, the browser sends a request that looks like this (it's just text):
GET /products?category=Coffee HTTP/1.1
Host: tokokita.id
User-Agent: Mozilla/5.0 ...
Accept: text/html
| Part | Here | Meaning |
|---|---|---|
| method | GET | what to do: GET reads, POST sends data (a form, an order) |
| path | /products | which resource |
| query string | category=Coffee | extra parameters after ?, as key=value pairs joined by & |
| headers | Host, User-Agent, Accept | metadata about the request |
| body | (empty for GET) | data sent with POST requests, like form fields or JSON |
Python can take a URL apart the same way a server does:
from urllib.parse import urlsplit, parse_qs
url = "https://tokokita.id/products?category=Coffee&sort=price"
parts = urlsplit(url)
print(parts.scheme, parts.netloc, parts.path)
print(parse_qs(parts.query))
https tokokita.id /products
{'category': ['Coffee'], 'sort': ['price']}
The response
The server answers with a status line, headers and a body:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 1534
<!doctype html><html>... the page ...</html>
The status code is a three-digit summary of what happened. The first digit tells you the family:
| Code | Family | Common examples |
|---|---|---|
| 2xx | success | 200 OK, 201 Created |
| 3xx | go somewhere else | 301 Moved Permanently, 302 Found (redirect) |
| 4xx | the client made a mistake | 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found |
| 5xx | the server failed | 500 Internal Server Error, 503 Service Unavailable |
The Content-Type header tells the browser how to treat the body: text/html is rendered as a page, application/json is data, text/csv is usually downloaded.
A server is a function
Strip away the networking, and a web application is one idea: a function from request to response. Here's a toy version in plain Python:
def handle(request):
"""A tiny web app: request dict in, response dict out."""
if request["method"] != "GET":
return {"status": 405, "body": "Method not allowed"}
if request["path"] == "/":
return {"status": 200, "body": "Selamat datang di Toko Kita!"}
if request["path"] == "/products":
return {"status": 200, "body": "15 products"}
return {"status": 404, "body": "Not found"}
print(handle({"method": "GET", "path": "/products"}))
print(handle({"method": "GET", "path": "/careers"}))
print(handle({"method": "DELETE", "path": "/"}))
{'status': 200, 'body': '15 products'}
{'status': 404, 'body': 'Not found'}
{'status': 405, 'body': 'Method not allowed'}
That chain of ifs works for three pages. For a real app it falls apart quickly, and it ignores everything a real server must handle.
What the framework does for you
| Job | Without a framework | With Flask |
|---|---|---|
| Speak HTTP: parse request text, write responses with correct headers | you, carefully | done |
Routing: map paths like /products/42 to the right function | a giant if chain | @app.route("/products/<int:id>") |
| Read query strings, forms, JSON, cookies, uploaded files | manual parsing | request.args, request.form, request.json |
| Build HTML from data safely | string concatenation (and security holes) | Jinja2 templates with auto-escaping |
| Errors: 404s, 500s, debugging | write it all | built in, customisable |
| Testing without a browser | hard | app.test_client() |
Flask is a micro-framework: it does these core jobs and stays out of your way for the rest (databases, login, admin pages come from extensions you choose). Django, the other big Python framework, includes much more out of the box. FastAPI specialises in JSON APIs. The request/response ideas in this track apply to all of them.
Where Flask sits
When someone opens a page on Toko Kita's site, a chain of programs passes the request along until your code answers it. It helps to picture that chain once, because error messages and deployment guides refer to each part of it:
browser ──HTTP──▶ web server (gunicorn / Flask's dev server) ──▶ your Flask app ──▶ your functions
◀──────────────────────── response ◀────────────────────────────────────────┘
The web server handles the network connections and passes each request to your Flask app using a Python standard called WSGI. Your app routes it to one of your functions and turns the return value into a response. In development, flask run gives you a small built-in server. In production, a robust server like gunicorn takes its place. Your code doesn't change.
Why this matters for clean code
"A web app is a function from request to response" is the most useful mental model you'll take from this track. It means each page or API endpoint can be a small function with clear inputs (the request) and a clear output (the response). That's exactly the kind of code that's easy to read, test and change. When a Flask app becomes messy, it's usually because views stopped being small functions and started doing everything.
Recap
- The browser sends a request (method, path, query string, headers, body); the server sends a response (status code, headers, body).
GETreads,POSTsends data. 2xx success, 3xx redirect, 4xx client error, 5xx server error.Content-Typesays what the body is: HTML, JSON, CSV...- A web app is a function from request to response; a framework handles HTTP, routing, input parsing, templates, errors and testing.
- Flask is a micro-framework; a WSGI server (gunicorn) runs it in production.