0%

De standaardclient en statusklassen · oefening

Elk scenario indelen

get_json leest de status en de headers die een beslissing nodig heeft. Nu kan het de klasseregel uit les 2 toepassen op elk antwoord, ook op de mislukkingen. practice-api heeft routes die met opzet mislukken, zodat je kunt zien hoe een client ze tegenkomt zonder iets kapot te maken. Deze les schrijft classify, voegt de klasse aan het record toe, en decodeert de body van elk -antwoord, foutbodies inbegrepen.

Vier manieren om te mislukken

Elk van deze doelen mislukt op een andere manier:

  • /v1/items/99: een item dat niet bestaat;

  • /v1/scenarios/not-found: een 404 die met opzet wordt gestuurd;

  • /v1/scenarios/server-error: een 500 die met opzet wordt gestuurd;

  • /v1/items?page=11&page_size=3: een paginanummer buiten bereik.

Elk ervan komt met een JSON-body, en de bodies hebben één vorm: een "error" met een "code" die een programma kan testen, een "message" die een mens kan lezen, en soms meer. Dit zijn de vier bodies die practice-api stuurt:

{"error":{"code":"not_found","message":"item not found","scenario":"resource"}}
{"error":{"code":"scenario_not_found","message":"intentional not found scenario","scenario":"not_found"}}
{"error":{"code":"scenario_server_error","message":"intentional server error scenario","scenario":"server_error"}}
{"error":{"code":"invalid_parameter","message":"page must be between 1 and 10"}}

Kijk naar de laatste. De status, 400, zegt alleen dat het verzoek fout was. De body zegt welk deel, en wat het zou oplossen: pagina’s lopen van 1 tot en met 10. Een client die bij elke 4xx een opwerpt voordat hij de body leest, zoals raise_for_status deed, verliest precies die zin. Twee van de bodies zijn 404’s, en alleen hun "code" vertelt je dat bij de ene een item ontbreekt, terwijl de andere route met opzet mislukte.

Waarom moet een client de body van een 404 houden?

De functie classify

classify(status) geeft de klasse van elke code terug als een woord dat een mens kan lezen:

status // 100classify geeft terug
1"informational"
2"success"
3"redirection"
4"client error"
5"server error"

Alles onder 100 of boven 599 is geen , en classify werpt er ValueError voor op. De regel is het eerste cijfer voor elke code in het bereik, ook voor codes die geen enkele van jou noemt: 299 is een "success" en 418 een "client error". Eén manier om het te schrijven is een lijst van de vijf namen, geïndexeerd met status // 100 - 1; een reeks en elif over status // 100 werkt ook.

Een sleutel data voor elke JSON-body

get_json voegt twee sleutels aan zijn record toe:

  • "class": classify(status), voor elk antwoord.

  • "data": de body gedecodeerd met json.loads(body.decode("utf-8")) als het antwoord als JSON gelabeld is en de body niet leeg is; anders None.

“Als JSON gelabeld” betekent dat het mediatype application/json is. De content_type uit les 3 kan een hebben, dus neem het deel vóór een eventuele ; met .split(";")[0], haal de spaties weg met .strip(), en vergelijk in kleine letters, omdat mediatypen hoofdletters negeren. Een antwoord zonder Content-Type, een text/plain-antwoord en een lege body laten "data" allemaal None, en "body" bevat nog steeds de bytes.

De status speelt in die beslissing geen rol. Een 404 die als JSON gelabeld is, wordt precies zo gedecodeerd als een 200, en zo bereikt de foutbody je aanroeper. En get_json werpt niets op vanwege een status: een 500 is een antwoord als elk ander, met als klasse "server error".

Eén geval werpt wel iets op. Een antwoord dat als JSON gelabeld is maar waarvan de body geen JSON is, laat json.loads json.JSONDecodeError opwerpen, een soort ValueError. Laat die door: het label en de body spreken elkaar tegen, en de aanroeper moet dat te horen krijgen. Decodeer na het with-blok of erbinnen; hoe dan ook is de verbinding gesloten als de exception get_json verlaat.

Je opdracht

  1. Schrijf in wire.py de classify(status).

  2. Voeg "class" en "data" toe aan het record dat get_json teruggeeft, zoals hierboven beschreven. Houd alles wat les 1 en 3 schreven.

  3. Voer alle vier de doelen uit:

python -c "
import wire
for target in ['/v1/items/99', '/v1/scenarios/not-found', '/v1/scenarios/server-error', '/v1/items?page=11&page_size=3']:
    record = wire.get_json(target)
    print(record['status'], record['class'], record['data'])
"

Als je code geschreven is, drukt het af:

404 client error {'error': {'code': 'not_found', 'message': 'item not found', 'scenario': 'resource'}}
404 client error {'error': {'code': 'scenario_not_found', 'message': 'intentional not found scenario', 'scenario': 'not_found'}}
500 server error {'error': {'code': 'scenario_server_error', 'message': 'intentional server error scenario', 'scenario': 'server_error'}}
400 client error {'error': {'code': 'invalid_parameter', 'message': 'page must be between 1 and 10'}}

Druk daarna op Check my work. Elk antwoord dat aankomt, heeft nu een klasse en houdt zijn body. De volgende les komt het geval tegen waarin helemaal geen antwoord aankomt.

Opdracht

Deel elk antwoord in op klasse en houd elke -body.

Schrijf classify(status) in wire.py. Het geeft "informational", "success", "redirection", "client error" of "server error" terug op basis van het eerste cijfer van de code, status // 100, voor elke code van 100 tot en met 599, en werpt op voor alles buiten dat bereik.

Voeg twee sleutels toe aan het record dat get_json teruggeeft:

  • "class": classify(status), voor elk antwoord.

  • "data": de body gedecodeerd met json.loads(body.decode("utf-8")) als het mediatype van content_type (het deel vóór een eventuele ;, vergeleken in kleine letters) application/json is en de body niet leeg is; anders None.

get_json werpt niets op vanwege een status: een 404 of een 500 geeft zijn record terug, met de body gedecodeerd zoals elke andere. Een body die als JSON gelabeld is maar geen JSON is, laat de ValueError van json.loads door, met de verbinding gesloten. Houd alles wat les 1 en 3 schreven.

Voer de vier mislukkende doelen uit in de , zoals de les laat zien.

Druk daarna op Check my work. Die roept classify aan met codes uit elke klasse, ook codes zoals 199 en 299 die geen met namen dekt, en met 99, 600 en 1000. Ze roept get_json aan met een vervanger voor make_connection waarvan je de gescripte antwoorden niet hebt gezien: 400, 404, 429, 500 en 503 met JSON-foutbodies, een 200 gelabeld als application/json zonder , een text/plain 418, een lege JSON-body, een antwoord zonder Content-Type, en een antwoord gelabeld als JSON waarvan de body HTML is. Niets uit je terminal wordt beoordeeld.