El mòdul 9 es va tancar amb una constatació incòmoda: Papyrus funciona, està provat i té xarxa de seguretat, però viu en un sol ordinador. Si en Lluís vol saber quants exemplars de Faust queden, ha de trucar a l'Anna; si la Júlia vol reservar Hamlet, ha d'acostar-se a la botiga. La solució té nom des de fa trenta anys: convertir Papyrus en una aplicació web, un programa que corre en un servidor i al qual qualsevol accedeix des d'un navegador o un mòbil. Abans d'escriure la primera línia de Flask (això arriba a la propera lliçó), necessites entendre el terreny de joc: com conversen un navegador i un servidor, què és HTTP, què hi pinta l'HTML en tot això i què et regala un framework. Aquesta lliçó és el mapa; les quatre següents, el viatge.
Contingut
- El model client-servidor: qui demana i qui respon
- HTTP: el protocol de la conversa
- Mètodes HTTP: els verbs de la web
- Codis d'estat: el semàfor de les respostes
- Anatomia d'una URL
- HTML: el mínim imprescindible per a aquest mòdul
- Frontend i backend: dos mons, una frontera
- JSON: l'idioma de les APIs (vell conegut)
- Què fa un framework per tu
- El panorama Python: Flask, Django i FastAPI
El model client-servidor: qui demana i qui respon
Tota la web se sosté sobre una idea simple: hi ha programes que demanen (clients) i programes que responen (servidors). El navegador d'en Lluís és un client; l'ordinador on correrà Papyrus serà un servidor. La conversa sempre la inicia el client — el servidor mai no truca a ningú per iniciativa pròpia, només espera peticions i les contesta.
sequenceDiagram
participant N as Navegador de Lluís (client)
participant S as Servidor de Papyrus
N->>S: GET /cataleg (petició HTTP)
Note over S: Executa codi Python:<br/>carregar_cataleg(), muntar la pàgina
S->>N: 200 OK + HTML del catàleg (resposta)
Note over N: El navegador dibuixa la pàgina
N->>S: GET /llibre/Faust
S->>N: 200 OK + fitxa de Faust (21.00 €, estoc 10)
Fixa't en el repartiment de papers:
- El client (navegador, app mòbil, o fins i tot un script Python amb
requests) construeix una petició, l'envia i espera. - El servidor rep la petició, executa codi — en el nostre cas, codi Python que ja tens escrit:
cercar_llibre(),vendre(),carregar_cataleg()— i retorna una resposta. - Cada intercanvi és independent: petició → resposta, i la connexió conceptualment s'acaba. Aquesta amnèsia del servidor (se'n diu sense estat, i hi tornarem a 10-03) és el que permet que milers de clients parlin amb el mateix servidor sense que aquest hagi de recordar cadascú.
La conseqüència pràctica per a Papyrus: el paquet papyrus/ que vas construir a M3–M9 no canvia. El que hi afegiràs és una capa per sobre que tradueix peticions HTTP en crides a les teves funcions, i els valors de retorn (o les excepcions) en respostes HTTP.
HTTP: el protocol de la conversa
HTTP (HyperText Transfer Protocol) és el format acordat d'aquestes peticions i respostes. És text, i és llegible. Una petició real té tres parts — línia inicial, capçaleres i cos opcional:
I la resposta, la mateixa estructura:
HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8 Content-Length: 1274 <!DOCTYPE html> <html>...la fitxa de Hamlet...</html>
- La línia inicial de la petició diu el mètode (
GET), la ruta (/llibre/Hamlet) i la versió del protocol. - Les capçaleres (headers) són metadades en format
Clau: valor— quin format accepta el client, quin format envia el servidor, quant ocupa el cos... - El cos (body) porta el contingut: HTML en una pàgina web, JSON en una API, res en moltes peticions GET.
No et caldrà escriure HTTP a mà mai — el navegador i el framework ho fan per tu —, però saber llegir-lo et convertirà en algú que depura problemes web en minuts en lloc d'hores.
Mètodes HTTP: els verbs de la web
El mètode declara la intenció de la petició. Amb quatre n'hi ha prou per a gairebé tot, i encaixen de manera natural amb les operacions que Papyrus ja sap fer:
| Mètode | Intenció | Exemple a Papyrus | Modifica dades? |
|---|---|---|---|
GET |
Llegir, consultar | Veure el catàleg, cercar L'Odissea | No |
POST |
Crear alguna cosa nova | Donar d'alta un llibre nou al catàleg | Sí |
PUT |
Actualitzar una cosa existent | Canviar l'estoc de Hamlet de 6 a 9 | Sí |
DELETE |
Eliminar | Retirar un llibre descatalogat | Sí |
Dues regles d'or que els frameworks respecten i tu també hauràs de respectar:
GETmai no ha de modificar dades. Un cercador que indexi la teva web seguirà tots els enllaços GET que trobi; si/vendre/Hamletfos un GET, un robot et podria buidar l'estoc sense voler.POST,PUTiDELETEporten la informació sensible al cos de la petició, no a la URL (les URLs acaben en logs i historials).
Codis d'estat: el semàfor de les respostes
Cada resposta HTTP comença amb un codi de tres xifres que resumeix com ha anat la cosa. La primera xifra és la família: 2xx èxit, 4xx el client s'ha equivocat, 5xx el servidor s'ha trencat. Aquests cinc són els que faràs servir constantment:
| Codi | Nom | Quan el retornarà Papyrus |
|---|---|---|
200 OK |
Èxit | GET /llibre/Hamlet i Hamlet existeix: aquí tens la seva fitxa |
201 Created |
Creat | POST d'un llibre nou acceptat: Faust II ja és al catàleg |
400 Bad Request |
Petició mal formada | POST d'un llibre sense titol o amb preu: "gratis" |
404 Not Found |
No existeix | GET /llibre/Rayuela — no el tenim (et sona LlibreNoTrobatError?) |
500 Internal Server Error |
Error del servidor | Una excepció no capturada al nostre codi Python |
La fila del 404 és un avançament important: a M7 vas dissenyar LlibreNoTrobatError per assenyalar exactament aquesta situació dins de Python. A 10-03 veuràs que la traducció excepció → codi d'estat és literal: captures LlibreNoTrobatError i respons 404. La teva jerarquia d'excepcions de M7 ja pensava en la web sense saber-ho.
I un matís d'actitud professional: un 500 sempre és culpa teva (o del teu codi). Si un usuari pot provocar un 500 escrivint alguna cosa estranya en un formulari, et falta validació — hauria de ser un 400 amb un missatge útil.
Anatomia d'una URL
La URL és l'adreça completa d'un recurs. Disseccionem una futura URL de Papyrus:
https://papyrus.example:443/llibres/cercar?titol=odissea&max=10#resultats └─┬─┘ └──────┬───────┘└┬┘└──────┬──────┘└─────────┬─────────┘└───┬────┘ esquema host port ruta query string fragment
- Esquema: el protocol,
httpohttps(lasés HTTP xifrat; avui, semprehttpsen producció). - Host: el nom del servidor. En desenvolupament serà
localhosto127.0.0.1— la teva pròpia màquina. - Port: la "porta" del servidor. S'omet si és l'estàndard (80 per a http, 443 per a https). El servidor de desenvolupament de Flask fa servir el 5000 i el de Django el 8000; els veuràs mil vegades.
- Ruta (path): quin recurs es demana. És el que les teves rutes de Flask/Django mapejaran a funcions.
- Query string: paràmetres opcionals després de
?, en parellsclau=valorseparats per&. És on viatgen els termes de cerca d'un formulari GET. - Fragment: després de
#, una posició dins de la pàgina; no arriba al servidor.
HTML: el mínim imprescindible per a aquest mòdul
Siguem honestos: això no és un curs d'HTML, i no intentarà ser-ho. Però les plantilles de Flask i Django generen HTML, així que necessites llegir-lo i escriure'n el bàsic. HTML és un llenguatge de marcatge: emboliques contingut entre etiquetes que declaren què és cada cosa.
<!DOCTYPE html>
<html lang="ca">
<head>
<meta charset="utf-8">
<title>Papyrus — Llibreria</title>
</head>
<body>
<h1>Catàleg de Papyrus</h1>
<p>Els clàssics de sempre, al teu barri.</p>
<ul>
<li>L'Odissea — 12.50 €</li>
<li>Hamlet — 9.95 €</li>
</ul>
<a href="/llibre/Faust">Mostra la fitxa de Faust</a>
</body>
</html>Línia a línia: <!DOCTYPE html> declara HTML modern; <head> conté metadades que no es pinten (codificació, títol de la pestanya); <body> és el que es veu; <h1> un encapçalament, <p> un paràgraf, <ul>/<li> una llista, <a href="..."> un enllaç. Les etiquetes s'obren <p> i es tanquen </p>.
La peça que més faràs servir és el formulari, perquè és com l'usuari envia dades al servidor:
<form action="/cercar" method="get">
<label for="titol">Cerca un llibre:</label>
<input type="text" id="titol" name="titol">
<button type="submit">Cerca</button>
</form>actionés la ruta a la qual s'envia;methodel verb HTTP (getper a cerques,postper crear/modificar).- Cada
<input>ambnamees converteix en un paràmetre: en cercar "odissea", el navegador demanaGET /cercar?titol=odissea. Aquí tens la query string d'abans. <button type="submit">dispara l'enviament.
Amb encapçalaments, paràgrafs, llistes, taules (<table>, <tr>, <td>), enllaços i formularis tens el 95 % del que aquest mòdul necessita.
Frontend i backend: dos mons, una frontera
| Frontend | Backend | |
|---|---|---|
| On s'executa | Al navegador de l'usuari | Al servidor |
| Llenguatges típics | HTML, CSS, JavaScript | Python (el nostre!), i molts d'altres |
| Responsabilitat | Presentació i interacció | Lògica de negoci, dades, seguretat |
| A Papyrus | Les pàgines que veuran en Lluís i la Júlia | cercar_llibre(), vendre(), el catàleg |
La frontera entre tots dos és exactament HTTP: el frontend demana, el backend respon. Aquest curs és de Python, així que viurem al backend; el frontend que escriurem serà HTML modest generat per plantilles, suficient perquè Papyrus sigui usable. Una regla que no has d'oblidar mai: tota validació del frontend és cortesia, no seguretat. Qualsevol pot enviar peticions HTTP sense passar pel teu formulari (ho faràs tu mateix amb curl a 10-03), així que el backend ha de validar sempre, es refiï o no de la pàgina que va servir.
JSON: l'idioma de les APIs (vell conegut)
Quan el client no és un navegador que vol HTML sinó un programa que vol dades — la futura app mòbil de la Júlia, un script d'en Lluís —, la resposta viatja en JSON. I aquí no hi ha res de nou a aprendre: és exactament el format de M6, el mateix de dades/cataleg.json:
json.dumps() convertia diccionaris en text JSON; asdict() (M5) convertia les teves dataclasses Llibre en diccionaris. La cadena Llibre → asdict() → JSON → resposta HTTP és la columna vertebral de la lliçó 10-03, i ja en coneixes dues de les tres baules. Una API (Application Programming Interface) web no és res més que un conjunt d'URLs pensades per a programes: mateixes peticions HTTP, mateixa estructura, però JSON en lloc d'HTML al cos.
Què fa un framework per tu
Podries escriure un servidor web amb la biblioteca estàndard de Python (http.server existeix), igual que podries escriure els teus propis tests sense pytest. Ningú no ho fa, per la mateixa raó: un framework web resol de sèrie els problemes que tota aplicació web comparteix.
- Encaminament: mapejar
GET /llibre/Hamleta la teva funció Python que sap respondre. Sense framework, seria unif/elifgegant sobre la ruta. - Plantilles: generar HTML barrejant una estructura fixa amb dades variables (el catàleg, el resultat d'una cerca), sense concatenar cadenes a mà.
- Formularis: llegir les dades enviades, convertir tipus, validar.
- Seguretat: protecció contra atacs clàssics (injecció d'HTML maliciós, falsificació de peticions) que ni tan sols sabies que existien — i dels quals parlarem a 10-05.
- Errors: convertir excepcions en respostes 404/500 raonables en lloc de deixar caure el servidor.
El framework s'ocupa de la fontaneria HTTP; tu escrius només allò que fa única la teva aplicació. A Papyrus, aquesta part única ja està escrita i provada: és el paquet papyrus/.
El panorama Python: Flask, Django i FastAPI
Python té tres frameworks dominants, i aquest mòdul t'ensenyarà els dos primers:
| Flask | Django | FastAPI | |
|---|---|---|---|
| Filosofia | Micro: nucli mínim, hi afegeixes el que necessites | Bateries incloses: ho porta tot | Modern, especialitzat en APIs |
| Corba d'aprenentatge | Suau: app en 5 línies | Més empinada: estructura i convencions | Suau si domines els type hints (M8) |
| Porta de sèrie | Rutes, plantilles, servidor de desenvolupament | A més: ORM (base de dades), admin, formularis, usuaris | Validació automàtica, documentació automàtica |
| Brilla en | Projectes petits/mitjans, APIs, aprendre | Aplicacions grans amb moltes peces estàndard | APIs d'alt rendiment (async, M8) |
| En aquest mòdul | 10-02 i 10-03 | 10-04 i 10-05 | Només aquesta menció honesta |
Tots tres s'instal·len com qualsevol paquet: pip install flask, pip install django — dins d'un entorn virtual, com vas aprendre a M1. FastAPI mereix la menció perquè és el tercer en discòrdia i fa servir intensivament els type hints de M8 i asyncio per a servidors asíncrons; si algun dia construeixes una API seriosa, dona-li un cop d'ull. Però per aprendre els fonaments, Flask primer (veuràs cada peça per separat) i Django després (veuràs què és tenir-les totes integrades) és el camí clàssic, i és el nostre.
Errors Comuns i Consells
- Confondre la URL amb la pàgina. La URL identifica el recurs; la pàgina és la resposta. Dues peticions a la mateixa URL poden retornar coses diferents (l'estoc canvia). Pensa en les URLs com a preguntes, no com a fitxers.
- Fer servir GET per a operacions que modifiquen dades. És l'error conceptual més perillós dels principiants. Si modifica alguna cosa: POST, PUT o DELETE. Sempre.
- Retornar 200 per a tot. Una API que respon
200 OKamb el cos{"error": "no trobat"}és una API mentidera: els clients automàtics miren primer el codi. Codis correctes des del primer dia. - Creure que cal dominar HTML/CSS/JavaScript abans de continuar. No. Amb l'HTML d'aquesta lliçó n'hi ha prou per a tot el mòdul. El backend és una especialitat completa per si mateixa.
- Oblidar que el servidor no recorda res entre peticions. Cada petició arriba òrfena. Els mecanismes per "recordar" usuaris (sessions, cookies) existeixen i els frameworks els donen fets, però el protocol base és amnèsic — i això és una virtut, com veuràs a 10-03.
Exercicis
Exercici 1: verbs i codis
Per a cada operació de Papyrus, indica el mètode HTTP adequat i el codi d'estat que hauria de retornar el servidor en l'escenari descrit:
- La Júlia consulta la fitxa d'El Quixot (existeix).
- L'Anna dona d'alta Faust II amb títol, preu i estoc vàlids.
- En Lluís consulta la fitxa de Rayuela (no és al catàleg).
- Un script envia una alta de llibre amb
"preu": "vint euros". - L'Anna actualitza l'estoc de Hamlet a 9 unitats.
Exercici 2: dissecció d'URL
Descompon en les seves parts (esquema, host, port, ruta, query string) la URL:
Quina parella clau=valor rebrà el servidor d'un formulari amb un únic <input> que té name="titol" si l'usuari escriu faust?
Exercici 3: el formulari de reserva
Escriu l'HTML d'un formulari perquè la Júlia reservi un llibre: un camp de text per al títol, un camp numèric (type="number") anomenat unitats, i un botó "Reserva". La reserva modifica dades (aparta estoc): tria action i method en conseqüència i justifica la tria en un comentari HTML (<!-- ... -->).
Solucions
Exercici 1:
GET→200 OK(lectura amb èxit).POST→201 Created(recurs nou creat).GET→404 Not Found(la petició està ben formada; el recurs no existeix — el casLlibreNoTrobatError).POST→400 Bad Request(el client ha enviat dades invàlides; validem i expliquem el motiu, mai no deixem que esclati en un 500).PUT→200 OK(actualització d'un recurs existent).
Exercici 2: esquema http, host localhost, port 5000 (el de desenvolupament de Flask), ruta /cercar, query string titol=quixot&soci=true (dos paràmetres: titol=quixot i soci=true). Amb l'input name="titol" i el valor faust, el servidor rep titol=faust — la URL resultant seria /cercar?titol=faust.
Exercici 3:
<!-- method="post" perque reservar modifica l'estoc: les operacions
amb efectes mai no han de viatjar en GET (els robots segueixen
enllacos GET i els parametres GET acaben en historials i logs). -->
<form action="/reservar" method="post">
<label for="titol">Títol:</label>
<input type="text" id="titol" name="titol">
<label for="unitats">Unitats:</label>
<input type="number" id="unitats" name="unitats" min="1">
<button type="submit">Reserva</button>
</form>Conclusió
Ja tens el mapa. La web és un diàleg de peticions i respostes HTTP entre clients que demanen i un servidor que executa codi — aviat, el teu codi. Els mètodes (GET llegeix, POST crea, PUT actualitza, DELETE esborra) declaren la intenció; els codis d'estat (200, 201, 400, 404, 500) resumeixen el resultat, i ja has vist que LlibreNoTrobatError i el 404 estan destinats a trobar-se. Saps llegir una URL peça a peça, escriure l'HTML mínim amb formularis inclosos, i distingir el frontend (presentació, al navegador) del backend (lògica i dades, en Python). I saps quin framework triaràs per a cada cosa: Flask per començar lleuger, Django quan vulguis les bateries incloses, FastAPI com a assignatura optativa futura. A la propera lliçó s'acaba la teoria: instal·laràs Flask al venv, escriuràs una aplicació completa en cinc línies, descobriràs que @app.route és exactament un d'aquells decoradors de 08-02, i posaràs el catàleg de Papyrus — L'Odissea, Hamlet, El Quixot i Faust — en un navegador per primera vegada.
Curs de Programació en Python
Mòdul 1: Introducció a Python
- Introducció a Python
- Configuració de l'Entorn de Desenvolupament
- Sintaxi de Python i Tipus de Dades Bàsics
- Variables i Constants
- Entrada i Sortida Bàsica
- Entorns Virtuals i Gestió de Paquets
Mòdul 2: Estructures de Control
Mòdul 3: Funcions i Mòduls
- Definició de Funcions
- Arguments de Funció
- Funcions Lambda
- Mòduls i Paquets
- Visió General de la Biblioteca Estàndard
Mòdul 4: Estructures de Dades
Mòdul 5: Programació Orientada a Objectes
Mòdul 6: Gestió de Fitxers
- Lectura i Escriptura de Fitxers
- Treball amb Fitxers CSV
- Gestió de Dades JSON
- Operacions amb Fitxers i Directoris
Mòdul 7: Gestió d'Errors i Excepcions
- Introducció a les Excepcions
- Gestió d'Excepcions
- Llançament d'Excepcions
- Excepcions Personalitzades
- Bones Pràctiques i Registre d'Errors amb logging
Mòdul 8: Temes Avançats
- Anotacions de Tipus (type hints)
- Decoradors
- Generadors
- Gestors de Context
- Concurrència: Fils i Processos
- Asyncio per a la Programació Asíncrona
Mòdul 9: Proves i Depuració
- Introducció a les Proves
- Proves Unitàries amb unittest
- Proves amb pytest
- Desenvolupament Guiat per Proves
- Tècniques de Depuració
- Ús de pdb per a la Depuració
Mòdul 10: Desenvolupament Web amb Python
- Introducció al Desenvolupament Web
- Fonaments del Framework Flask
- Construcció d'APIs REST amb Flask
- Introducció a Django
- Construcció d'Aplicacions Web amb Django
Mòdul 11: Ciència de Dades amb Python
- Introducció a la Ciència de Dades
- NumPy per a la Computació Numèrica
- Pandas per a la Manipulació de Dades
- Matplotlib per a la Visualització de Dades
- Introducció a l'Aprenentatge Automàtic amb scikit-learn
