Doorverwijzingen · eindproject
Eindproject: Project: boeken die verhuisd zijn
Je hebt beide helften van een /v0/books-paden met een 308 die de id en de querystring behoudt, en je follow lost een location op, behoudt of verandert de pl_http.py follow, maar elke controle tot nu toe bewees één helft tegelijk, tegen vervangers. En niets wat je tot nu toe hebt geschreven, stuurt een schrijfactie door de volger: follow neemt een body, maar geen enkele send_json, en laat zien dat de PUT van een oude client het boek bereikt dat hij bedoelde, via de doorverwijzing van je server, in één hop.
Wat send_json doet
send_json(method, url, data, *, make_connection, max_hops, timeout) is de client die een oude leeslijst-app zou aanroepen om een boek op te slaan:
Codeer
dataalsin -bytes: json.dumps(data, ensure_ascii=False).encode("utf-8"), zoals dejson_responsevan je server doet.Stuur het met
follow, met de body, een headerContent-Type: application/json, enmake_connection,max_hopsentimeoutprecies zoalssend_jsonze kreeg.Voeg
"data"toe aan het record datfollowteruggaf: de body gedecodeerd als UTF-8-JSON als decontent-typevan het antwoordapplication/jsonis (zoals ; charset=utf-8toegestaan) en de body niet leeg is, en andersNone.get_jsonnam in hoofdstuk 3 dezelfde beslissing.
Elke status is een record, zoals eerder. Een 422 van de server komt terug met de fout in "data"; send_json werpt alleen op wat follow opwerpt, zoals TimeoutError als een server stil blijft.
Ongeveer acht regels zijn genoeg, omdat het moeilijke deel al in follow zit. Kijk wat follow met deze body doet als hij een doorverwijzing tegenkomt: na een 308 gaan de PUT en zijn body ongewijzigd naar het nieuwe pad; na een 303 vallen de body en de content-type ervan weg. De 308 van je server en de regel van je volger voor 308 moeten het met elkaar eens zijn, anders gaat de schrijfactie van een oude client verloren.
Mijlpalen
Schrijf eerst send_json. Voer daarna het scenario agree van het hulpprogramma uit:
python pl_http.py agree
Het roept je send_json("PUT", "http://books.test/v0/books/2", ...) aan met een nieuwe titel voor boek 2, tegen je eigen server op deze machine. Je zou twee verzoeken moeten zien en daarna de data die je server heeft opgeslagen:
request 1 PUT /v0/books/2 -> 308 Permanent Redirect
request 2 PUT /books/2 -> 200 OK
...
data: {'id': 2, 'title': 'Café Society (2nd edition)', 'author': 'Ana Ruiz'}
Daarna stuurt het hulpprogramma zijn eigen GET /books/2, en dat antwoord draagt ook de nieuwe titel: de schrijfactie bereikte het actuele pad, en maar één keer.
Dan de loop uit:
python pl_http.py loop
Hier draait je server een kleine handler die voor deze cursus is geschreven en in een cirkel doorverwijst: /a antwoordt met 307 naar /b, en /b antwoordt met 307 naar /a. Het hulpprogramma roept je follow("GET", "http://books.test/a", max_hops=3, ...) aan. Een correcte volger stuurt vier verzoeken en werpt ValueError op; het transcript toont request 1 tot en met request 4, allemaal 307 Temporary Redirect, daarna raised ValueError met jouw melding, en het scenario eindigt met status 0, omdat de fout hier de juiste uitkomst is. Het hulpprogramma geeft de server vijf verbindingen en opent zelf de verbinding die je volger niet gebruikte, wat het meldt als pl_http opened 1 empty connection(s) so serve() could stop waiting. Een volger zonder limiet gaat door tot de server gestopt is, en mislukt in plaats daarvan met ConnectionRefusedError.
Optioneel: test send_json zelf. fakes.py heeft nu scripted_connections(responses, calls): een make_connection waarvan de verbindingen met de gegeven antwoorden reageren, op volgorde, één per verbinding, en die per verbinding de host, scripted_connections toe aan de regel from fakes import van tests/test_wire.py, en een test zoals:
def test_send_json_follows_a_308():
calls = []
moved = scripted_response(308, "Permanent Redirect", [["location", "/books/2"]], b"")
stored = scripted_response(200, "OK", [["content-type", "application/json"]], b'{"id": 2, "title": "Dune"}')
connections = scripted_connections([moved, stored], calls)
record = wire.send_json("PUT", "http://books.test/v0/books/2", {"title": "Dune"}, make_connection=connections)
assert record["data"] == {"id": 2, "title": "Dune"}
assert calls[1]["requests"][0]["method"] == "PUT"
assert calls[1]["closed"]
Voer je tests uit vanuit de projectmap:
python -m pytest -q
Ze zijn van jou; Check my work voert ze niet uit.
Wat er bewezen wordt, en hoe
Check my work bewijst de overeenstemming zonder send_json met je eigen reading_server.handle in één proces: de verbinding die hij aan je volger geeft, bouwt een verzoek-read_body en handle, zoals http_adapter zou doen, en maakt van de antwoord-dict weer een antwoord. De 308 die je volger leest, is dus de 308 die je server schreef, en de PUT die hij herhaalt, verandert de state die je server bijhoudt. De runs agree en loop laten hetzelfde zien over een echte verbinding op deze machine. Die runs zijn om naar te kijken; ze worden niet beoordeeld.
Klik daarna op Check my work.
Elk verzoek in deze cursus stond tot nu toe op zichzelf: de server vergat elke client op het moment dat hij antwoordde, en geen client kon bewijzen wie hij was. Hoofdstuk 7 geeft de leeslijst een geheugen van wie er vraagt, met een sessie die in een
Opdracht
Schrijf send_json(method, url, data, *, make_connection, max_hops, timeout) in wire.py, zodat een
Codeer
dataals JSON in-bytes. Stuur het met
follow(method, url, ...), met die body, een headerContent-Type: application/json, en demake_connection,max_hopsentimeoutdiesend_jsonkreeg.Geef het record terug dat
followteruggaf, met"data"erbij: de body gedecodeerd als UTF-8-JSON als decontent-typevan het antwoordapplication/jsonis (met of zonder) en de body niet leeg is, anders None.Elke status is een record. Laat
bij de hoplimiet, en elke andere exception uit follow, uitsend_jsonnaar buiten komen.
De follow uit les 4 moeten nog steeds werken: deze controle laat ze samen draaien. Voer python pl_http.py agree en python pl_http.py loop uit in de
Klik daarna op Check my work. Die geeft send_json een make_connection waarvan de verbindingen elk verzoek, als verzoek-read_body en reading_server.handle sturen, met een state met boeken die je nog niet hebt gezien, en de antwoord-dict van je server weer omzetten in een antwoord; er wordt geen PUT naar een oud pad met een querystring het boek verandert na precies één 308 en 200 teruggeeft met het opgeslagen boek in "data"; dat een POST naar /v0/books na één 308 een boek aanmaakt met 201; dat een 422 terugkomt als record met de fout in "data"; dat een antwoord zonder body, of met een body die geen JSON is, "data" None geeft; dat een POST die met 303 wordt beantwoord, doorgaat als GET zonder body; dat een doorverwijslus ValueError opwerpt na max_hops + 1 verzoeken; en dat de time-out elke verbinding bereikt. Je eigen tests worden niet uitgevoerd. Niets uit je terminal wordt beoordeeld.