Hoofdstuk 12 · eindproject
Eindproject: de leeslijstservice en -client
Eindproject: De server afmaken
Hoofdstuk 11 bouwde de leeslijst opnieuw in requests-client uit hoofdstuk 10, en vraagt beide om tegelijk aan één document te voldoen: SERVICE_CONTRACT.md.
Het contract ligt vast. Niets in dit hoofdstuk verandert er een route, een status, een header of een exitcode in. Twee programma’s vertrouwen nu op dezelfde woorden. Als de server location: /books/3 stuurt, maakt de client er een
Lees het contract, vind de gaten
Open SERVICE_CONTRACT.md in het tabblad Project en scrol naar de laatste sectie, “Not built yet” (nog niet gebouwd). Die noemt drie rijen. Elke rij heeft een serverhelft, die je in deze les herstelt, en een clienthelft, die de volgende twee lessen bouwen:
| Rij | Serverhelft (deze les) | Clienthelft |
|---|---|---|
| Oude paden | elke /v0/books en /v0/books/... krijgt een 308 naar hetzelfde pad zonder /v0, met behoud van de query | een regel followed 308 from URL voor elke |
| Hervalidatie | een overeenkomende If-None-Match maakt van een 200 voor een leesverzoek een 304 zonder body | een cachebestand dat show hergebruikt zolang het vers is en hervalideert als het verlopen is (les 2) |
| Nieuwe boeken | de 201 voor POST /books draagt location: /books/{id} | add drukt de absolute URL van het nieuwe boek af (les 2) |
Geen van de serverhelften is nieuw voor je. De location-regel komt uit hoofdstuk 5, legacy_location en de 308-tak uit hoofdstuk 6, en etag_matches, not_modified en de 304-regel uit hoofdstuk 8. Ze zijn uit een verder afgemaakte server gehaald, zodat de clienthelften iets hebben om mee overeen te stemmen.
De rest van reading_server.py is de nagekeken server van het eind van hoofdstuk 9: read_body die na elke weigering de verbinding sluit, inloggen en sessies, bearer-tokens, en etag en cache-control op elke 200 voor een leesverzoek. Laat die zoals hij is. Check my work bewijst die rijen opnieuw, met boeken, gebruikers en tokens die je niet hebt gezien, omdat een wijziging op de ene plek een rij ver weg kan breken.
Mijlpalen
Eerst de oude paden. Schrijf legacy_location(target): neem het pad met urlsplit(target).path, knip de eerste drie tekens eraf, /v0, en voeg ? en de query toe als die er is. Werk vanuit het ruwe target, niet vanuit de gedecodeerde segmenten, zodat de handle toe, vóór elke andere route: als de eerste twee segmenten v0 en books zijn, is het antwoord redirect(308, legacy_location(request["target"])). Hij komt eerst, zodat een schrijfverzoek naar een oud pad wordt doorverwezen voordat het token wordt gecontroleerd, en er niets wordt opgeslagen.
Dan de hervalidatie. Schrijf etag_matches(values, etag): values is de if-none-match-regels, en elke regel kan meerdere tags bevatten, gescheiden door komma’s. Strip elk element, haal een W/ aan het begin weg, en geef True terug voor * of voor een tag die gelijk is aan etag. Schrijf not_modified(response): een nieuwe antwoord-etag en cache-control van de 200 gekopieerd, en de body b"". Voeg dan de regel aan handle toe, na de routering en vóór de regels voor no-store en HEAD: als het antwoord een etag heeft en het verzoek if-none-match stuurde, en die twee overeenkomen, wordt het antwoord not_modified(response). Alleen een 200 voor een leesverzoek draagt een etag, dus fouten en schrijfverzoeken blijven ongemoeid, en * op een ontbrekend boek krijgt nog steeds zijn 404.
Dan de location. Voeg in create_book één regel toe vóór de location gezet op /books/ plus het nieuwe id. De client zet deze relatieve waarde in les 2 om.
Twee helperruns uit eerdere hoofdstukken werken nog steeds op deze server:
python pl_http.py moved
python pl_http.py conditional
In de moved-run zou het log van je server 308 moeten tonen voor de twee /v0-verzoeken waar de server waarmee je dit hoofdstuk begon 404 antwoordde. In de conditional-run zou het log 200, 304, 304, 200 moeten tonen: de eerste GET krijgt de tag, de volgende GET en de HEAD sturen hem terug en krijgen 304, en het laatste verzoek stuurt een verouderde tag en krijgt de hele lijst opnieuw.
Welke functie van de client werkt niet meer als de 304-regel van de server ontbreekt?
Je tests
tests/test_server.py roept handle rechtstreeks aan met make_request, zoals sinds hoofdstuk 5. Voer het uit na elke mijlpaal:
python -m pytest -q
Elke test die met het project meekwam, zou nog moeten slagen. Les 4 voegt tests toe voor de drie rijen.
Je opdracht
Schrijf
legacy_location, en de 308-tak bovenaanhandle.Schrijf
etag_matchesennot_modified, en de 304-regel inhandle.Voeg
locationtoe aan de 201 increate_book.Voer
python -m pytest -quit, en daarna de twee helperruns.Klik op Check my work.
Als een controle mislukt, noemt de melding het verzoek en de regel. Vraag Monty om die samen met je naast de bijbehorende tabel in SERVICE_CONTRACT.md te lezen, zonder de oplossing te schrijven.
De server voldoet nu aan elke serverrij van het contract. De client downloadt nog steeds elk boek elke keer opnieuw en drukt een nieuw boek af zonder zijn URL; de volgende les verhelpt beide.
Opdracht
Maak de serverhelft van SERVICE_CONTRACT.md af: de drie serverrijen onder “Not built yet”.
legacy_location(target): het pad van het target zonder de eerste drie tekens,/v0, met?en de query erachter als die er is. Bovenaanhandle, vóór elke andere route, krijgt een pad waarvan de eerste twee segmentenv0enbookszijnredirect(308, legacy_location(request["target"])), voor elke. etag_matches(values, etag):Trueals een element van eenif-none-match-regel, gestript en zonderW/aan het begin, gelijk is aanetag, of*is.not_modified(response): een 304 met alleen deetagencache-controlvan de 200 en de bodyb"". Inhandle, na de routering en vóór de regels voorno-storeenHEAD, wordt een antwoord met eenetagwaarmee deif-none-matchvan het verzoek overeenkomtnot_modified(response).In
create_bookdraagt de 201location: /books/{id}.
Houd elke andere rij van het contract zoals de server er al aan voldoet. Voer python -m pytest -q, python pl_http.py moved en python pl_http.py conditional uit in de
Klik daarna op Check my work. Die roept handle aan met boeken, gebruikers en tokens die je niet hebt gezien (de id’s 7, 41 en 1000, de gebruiker zoë), en controleert: leesverzoeken, HEAD, 404’s en 405 met allow; dat content-length bij elke body past, op bytes die de handlerklasse van je server in het geheugen schrijft; de location van de 201, gelezen tegen de GET, HEAD, POST, PUT en DELETE op /v0-paden met een percent-gecodeerde query; inloggen, de HttpOnly-/me en uitloggen; 401 en 403 voor schrijfverzoeken; etag en cache-control met MAX_AGE op 45; de 304 voor één tag, een W/ en *, eindigend bij de lege regel; drie verzoeken op één verbinding, en een weigering die haar sluit; en make_server en serve met een vervangende server die verbindingen telt. Niets opent een