0%

Doorverwijzingen · eindproject

Eindproject: Project: boeken die verhuisd zijn

Je hebt beide helften van een . Je server beantwoordt /v0/books-paden met een 308 die de id en de querystring behoudt, en je follow lost een location op, behoudt of verandert de naar status, en stopt bij een hoplimiet. Je hebt ze samen laten draaien via 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 bouwt er een. Dit project schrijft die functie, 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:

  1. Codeer data als in -bytes: json.dumps(data, ensure_ascii=False).encode("utf-8"), zoals de json_response van je server doet.

  2. Stuur het met follow, met de body, een header Content-Type: application/json, en make_connection, max_hops en timeout precies zoals send_json ze kreeg.

  3. Voeg "data" toe aan het record dat follow teruggaf: de body gedecodeerd als UTF-8-JSON als de content-type van het antwoord application/json is ( zoals ; charset=utf-8 toegestaan) en de body niet leeg is, en anders None. get_json nam 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 bij de hoplimiet of 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 . Voer het scenario 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, , time-out, verzoeken en of hij werd gesloten vastleggen. Voeg 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 . Hij verbindt je send_json met je eigen reading_server.handle in één proces: de verbinding die hij aan je volger geeft, bouwt een verzoek- uit wat je code verstuurt, stuurt die door je 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 wordt bijgehouden en een token dat bepaalt wie mag schrijven.

Opdracht

Schrijf send_json(method, url, data, *, make_connection, max_hops, timeout) in wire.py, zodat een -schrijfactie door je volger gaat en het actuele pad bereikt.

  • Codeer data als JSON in -bytes.

  • Stuur het met follow(method, url, ...), met die body, een header Content-Type: application/json, en de make_connection, max_hops en timeout die send_json kreeg.

  • Geef het record terug dat follow teruggaf, met "data" erbij: de body gedecodeerd als UTF-8-JSON als de content-type van het antwoord application/json is (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, uit send_json naar buiten komen.

De van je server uit les 3 en je 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 om ze op een echte verbinding aan het werk te zien.

Klik daarna op Check my work. Die geeft send_json een make_connection waarvan de verbindingen elk verzoek, als verzoek-, door je eigen 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 geopend. Hij controleert dat een 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.