0%

Bodies van verzoeken en een JSON-API · oefening

Aanmaken, vervangen, verwijderen

De tabel uit de vorige les zegt wat elke schrijfactie doet en als antwoord geeft. Je server doet daar nog niets van. Voer het schrijfscenario van het hulpprogramma uit in het tabblad Shell:

python pl_http.py writes

Het stuurt POST /books met een nieuw boek, en daarna GET, PUT, DELETE en nog eens GET op /books/3, de id die het nieuwe boek zou moeten krijgen. Vandaag krijgt de POST 405, omdat /books alleen GET en HEAD toestaat, en krijgen de vier verzoeken voor /books/3 404, omdat er nooit een boek 3 is aangemaakt. Aan het eind van deze les laat dezelfde run zien hoe het boek verschijnt, verandert en verdwijnt.

In deze les is elke body een geldig boek: een - met een title en author, gelabeld als application/json. Les 5 voegt de controles toe voor al het andere.

201 en location

Een POST /books die een boek opslaat, antwoordt met 201 Created. De body is het boek zoals het is opgeslagen, inclusief id, en een header location zegt waar het nieuwe boek staat. Hier is het antwoord, zonder de regels Server en Date:

HTTP/1.0 201 Created
content-type: application/json
content-length: 58
location: /books/3

{"id": 3, "title": "Piranesi", "author": "Susanna Clarke"}

Een 200 zou ook zeggen dat het verzoek gelukt is; 201 zegt meer, namelijk dat er nu een nieuwe resource bestaat, en location zegt waar. location: /books/3 is een pad, geen volledige . staat dat toe: een client lost een relatieve Location op ten opzichte van de URL die hij heeft opgevraagd (RFC 9110, sectie 10.2.2), op dezelfde manier waarop een browser een link op een pagina oplost. In hoofdstuk 6 schrijf je die oplossing voor je client. De id in het pad is de id die de server koos, dus de client leert hem uit het antwoord zonder de body te parsen.

De id komt uit state["next_id"]. Lees hem, sla het boek eronder op en tel er 1 bij op, zodat de volgende POST de volgende id krijgt. Een id in de body wordt genegeerd: bij POST kiest de server de id’s.

Wat moet location zeggen nadat POST /books boek 41 heeft aangemaakt?

204 betekent geen body

Een DELETE die een boek verwijdert, antwoordt met 204 No Content: succes, zonder iets te versturen. Een 204 heeft per definitie geen body, dus hij draagt ook geen content-length (RFC 9110, sectie 8.6, verbiedt die op een 204). Dat sluit json_response(204, ...) uit, dat beide toevoegt. Bouw dit antwoord met de hand:

Try it

Op de verbinding is het een statusregel, de regels Server en Date die http.server toevoegt, en de lege regel. Daarna volgt niets.

Clients gaan verschillend om met een 204. http.client weet dat een 204 geen body heeft en leest daarna niets. De fetch in je wire.py, geschreven in hoofdstuk 1, kent alleen HEAD als verzoek zonder body, dus bij een 204 zonder content-length werpt hij op, dezelfde weigering die hij geeft bij elk antwoord zonder lengte. Als je handle bij een 204 wel een body teruggaf, zou http.server die toch versturen, en zou pl_http.py de verdwaalde bytes op een eigen regel onder het antwoord tonen, zoals (5 bytes followed the reply: b'stray').

Welk antwoord op DELETE /books/41 is juist voor deze server?

Vervangen betekent alles

PUT /books/7 vervangt boek 7 door wat de body zegt. Het nieuwe boek wordt gebouwd uit de title en author van de body en de id uit de URL, 7, nooit uit de body. Bouw een nieuwe in plaats van de oude bij te werken: PUT vervangt, dus van het oude boek blijft niets over behalve zijn id. Het antwoord is 200 OK met het opgeslagen boek.

Een PUT of DELETE naar een id zonder boek krijgt 404, en dat beantwoordt je handle al voordat hij naar de kijkt. Houd dat zo: de schrijffuncties worden alleen aangeroepen voor een boek dat bestaat.

Jouw opdracht

In reading_server.py is de body al gelezen en, in deze les, geldig. Gebruik de meegeleverde json_body(request) om hem te decoderen.

  1. create_book(request, state): sla {"id": ..., "title": ..., "author": ...} op onder state["next_id"], tel 1 op bij next_id, en geef json_response(201, book) terug met een toegevoegde header location: /books/ gevolgd door de id.

  2. replace_book(request, state, book_id): sla een nieuw boek op met book_id en de title en author van de body; geef json_response(200, book) terug.

  3. delete_book(state, book_id): verwijder het boek en geef de 204-dict van hierboven terug.

  4. Roep in handle create_book aan voor POST op /books, en replace_book en delete_book voor PUT en DELETE op /books/{id}. Verander de allow- in GET, HEAD, POST voor de collectie en GET, HEAD, PUT, DELETE voor een item.

Voer python pl_http.py writes opnieuw uit. De POST krijgt nu HTTP/1.0 201 Created met location: /books/3, de GET leest het nieuwe boek, de PUT krijgt 200 OK met de nieuwe titel, de DELETE krijgt HTTP/1.0 204 No Content met daarna niets dan de lege regel, en de laatste GET krijgt 404: het boek is weg.

Klik daarna op Check my work. Hierna stopt de server met bodies vertrouwen: elke soort fout verzoek krijgt een eigen status.

Opdracht

Laat de drie schrijfacties werken, voor bodies die geldige boeken zijn.

Decodeer in reading_server.py de body met de meegeleverde json_body(request) en schrijf:

  1. create_book(request, state): sla {"id": ..., "title": ..., "author": ...} op onder state["next_id"], met de title en author van de body, en tel daarna 1 op bij state["next_id"]. Geef json_response(201, book) terug met een toegevoegde header location waarvan de /books/ gevolgd door de nieuwe id is.

  2. replace_book(request, state, book_id): sla een nieuw boek op met id book_id en de title en author van de body, en geef json_response(200, book) terug. De id komt altijd uit de , nooit uit de body.

  3. delete_book(state, book_id): verwijder het boek en geef {"status": 204, "headers": {}, "body": b""} terug: geen body en geen content-length.

  4. In handle: POST op /books roept create_book aan; PUT en DELETE op /books/{id} roepen replace_book en delete_book aan zodra vaststaat dat het boek bestaat (een onbekende id krijgt nog steeds 404). De 405-antwoorden noemen GET, HEAD, POST op /books en GET, HEAD, PUT, DELETE op /books/{id}.

In deze les is de body van elk verzoek een - met title en author, gelabeld als application/json. Les 5 handelt de rest af.

In de maakt python pl_http.py writes via je server een boek aan, leest het, vervangt het en verwijdert het.

Klik daarna op Check my work. Die roept handle aan met een state en boeken die je nog niet hebt gezien: twee POSTs, een PUT die twee keer wordt gestuurd, een DELETE, schrijfacties naar id’s waar geen boek staat, leesacties na de schrijfacties, en die een pad niet accepteert. Bodies bevatten een id die genegeerd moet worden. Hij controleert statussen, location, de opgeslagen state, next_id, en dat een 204 geen body en geen content-length heeft. Daarna stuurt hij een POST en een DELETE in het geheugen door de adapter, met jouw read_body, en leest hij de bytes. Niets uit je terminal wordt beoordeeld.