Der Standard-Client und die Statusklassen · Übung
Jedes Szenario einordnen
get_json liest den Status und die Header, die eine Entscheidung braucht. Jetzt kann es die Klassenregel aus Lektion 2 auf jede Antwort anwenden, auch auf die Fehlschläge. practice-api hat Routen, die absichtlich fehlschlagen, damit du zusehen kannst, wie ein Client ihnen begegnet, ohne etwas kaputtzumachen. Diese Lektion schreibt classify, fügt dem Datensatz die Klasse hinzu und dekodiert den Body jeder
Vier Arten fehlzuschlagen
Jedes dieser Ziele schlägt auf eine andere Art fehl:
/v1/items/99: ein Eintrag, den es nicht gibt;/v1/scenarios/not-found: ein absichtlich gesendetes 404;/v1/scenarios/server-error: ein absichtlich gesendetes 500;/v1/items?page=11&page_size=3: eine Seitennummer außerhalb des Bereichs.
Jedes davon kommt mit einem JSON-Body, und die Bodys haben eine Form: ein "error" mit einem "code", den ein Programm prüfen kann, einer "message", die ein Mensch lesen kann, und manchmal mehr. Das sind die vier Bodys, die practice-api sendet:
{"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"}}
Sieh dir den letzten an. Der Status, 400, sagt nur, dass die Anfrage falsch war. Der Body sagt, welcher Teil, und was ihn beheben würde: Seiten gehen von 1 bis 10. Ein Client, der bei jedem 4xx eine raise_for_status es getan hat, verliert genau diesen Satz. Zwei der Bodys sind 404, und nur ihr "code" sagt dir, dass bei einem ein Eintrag fehlt, während die andere Route absichtlich fehlgeschlagen ist.
Warum sollte ein Client den Body eines 404 behalten?
Die Funktion classify
classify(status) gibt die Klasse jedes Codes als ein Wort zurück, das ein Mensch lesen kann:
status // 100 | classify gibt zurück |
|---|---|
| 1 | "informational" |
| 2 | "success" |
| 3 | "redirection" |
| 4 | "client error" |
| 5 | "server error" |
Alles unter 100 oder über 599 ist kein classify löst dafür ValueError aus. Die Regel ist die erste Ziffer, für jeden Code im Bereich, auch für Codes, die keine deiner "success" und 418 ein "client error". Eine Möglichkeit, das zu schreiben, ist eine Liste der fünf Namen, indiziert mit status // 100 - 1; eine Kette aus elif über status // 100 funktioniert ebenso.
Ein Schlüssel data für jeden JSON-Body
get_json fügt seinem Datensatz zwei Schlüssel hinzu:
"class":classify(status), für jede Antwort."data": der Body, dekodiert mitjson.loads(body.decode("utf-8")), wenn die Antwort als JSON ausgezeichnet ist und der Body nicht leer ist; sonstNone.
“Als JSON ausgezeichnet” bedeutet, dass der Medientyp application/json ist. Das content_type aus Lektion 3 kann einen ; mit .split(";")[0], entferne die Leerzeichen mit .strip() und vergleiche in Kleinbuchstaben, weil bei Medientypen die Schreibweise keine Rolle spielt. Eine Antwort ohne Content-Type, eine Antwort mit text/plain und ein leerer Body lassen "data" alle auf None, und "body" enthält weiterhin die Bytes.
Der Status spielt bei dieser Entscheidung keine Rolle. Ein als JSON ausgezeichnetes 404 wird genau wie ein 200 dekodiert, und so erreicht der Fehler-Body deinen Aufrufer. Und get_json löst wegen eines Status nichts aus: Ein 500 ist eine Antwort wie jede andere, mit der Klasse "server error".
Ein Fall löst doch etwas aus. Eine als JSON ausgezeichnete Antwort, deren Body kein JSON ist, bringt json.loads dazu, json.JSONDecodeError auszulösen, eine Art von ValueError. Lass sie durch: Auszeichnung und Body widersprechen sich, und der Aufrufer sollte davon erfahren. Dekodiere nach dem with-Block oder darin; so oder so ist die Verbindung geschlossen, wenn die Ausnahme get_json verlässt.
Deine Aufgabe
Schreibe in
wire.pydieclassify(status).Füge dem Datensatz, den
get_jsonzurückgibt,"class"und"data"hinzu, wie oben beschrieben. Behalte alles, was die Lektionen 1 und 3 geschrieben haben.Führe alle vier Ziele aus:
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'])
"
Wenn dein Code geschrieben ist, gibt es Folgendes aus:
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'}}
Drücke dann Check my work. Jede Antwort, die ankommt, hat jetzt eine Klasse und behält ihren Body. Die nächste Lektion begegnet dem Fall, in dem überhaupt keine Antwort ankommt.
Aufgabe
Ordne jede Antwort nach Klasse ein und behalte jeden
Schreibe classify(status) in wire.py. Die "informational", "success", "redirection", "client error" oder "server error" aus der ersten Ziffer des Codes zurück, status // 100, für jeden Code von 100 bis 599, und löst
Füge dem Datensatz, den get_json zurückgibt, zwei Schlüssel hinzu:
"class":classify(status), für jede Antwort."data": der Body, dekodiert mitjson.loads(body.decode("utf-8")), wenn der Medientyp voncontent_type(der Teil vor einem eventuellen;, in Kleinbuchstaben verglichen)application/jsonist und der Body nicht leer ist; sonstNone.
get_json löst wegen eines Status nichts aus: Ein 404 oder ein 500 gibt seinen Datensatz zurück, mit seinem Body dekodiert wie jeder andere. Ein als JSON ausgezeichneter Body, der kein JSON ist, lässt den ValueError aus json.loads durch, mit geschlossener Verbindung. Behalte alles, was die Lektionen 1 und 3 geschrieben haben.
Führe die vier fehlschlagenden Ziele im
Drücke dann Check my work. Die Prüfung ruft classify mit Codes aus jeder Klasse auf, darunter Codes wie 199 und 299, die keine get_json mit einem Ersatz für make_connection auf, dessen geskriptete Antworten du nicht gesehen hast: 400, 404, 429, 500 und 503 mit JSON-Fehler-Bodys, ein 200 mit application/json ohne text/plain, ein leerer JSON-Body, eine Antwort ohne Content-Type und eine als JSON ausgezeichnete Antwort, deren Body HTML ist. Nichts aus deinem Terminal wird bewertet.