0%

Wat een framework voor je doet

Bekijk de bytes van FastAPI

Elk antwoord dat je app tot nu toe stuurde, ging als Python- van naar TestClient. Geen byte ervan ging over een , dus je hebt nog niet gezien hoe de 404 van FastAPI er op de lijn uitziet. Dat werk doet een serverprogramma: het accepteert verbindingen, leest de bytes van verzoeken, geeft elk verzoek aan de app, en schrijft het antwoord van de app als bytes. Voor FastAPI is dat programma vaak uvicorn, en de helper van dit hoofdstuk kan het voor je draaien.

Een server die stopt

Elke server in deze cursus is begrensd, en deze ook. pl_http bindt een socket aan 127.0.0.1 op een die het systeem kiest, zoals je make_server deed, geeft die socket aan uvicorn, en zegt uvicorn dat hij na drie verzoeken moet stoppen. Daarna stuurt het drie verzoeken met wire.fetch uit wire.py, de client uit hoofdstuk 9, en drukt het de bytes in beide richtingen af. uvicorn stopt kort na het derde antwoord vanzelf en sluit zijn luistersocket. Als de client eerder klaar was, zou pl_http uvicorn zeggen dat hij moet stoppen en er hooguit 2 seconden op wachten. Geen enkele server in deze cursus wacht tot jij hem met de hand stopt.

Draai het in het tabblad Shell:

python pl_http.py uvicorn

Met de uit les 1 op hun plaats is de eerste uitwisseling GET /books. Net als in eerdere hoofdstukken noemt de regel Host books.test, terwijl de verbinding naar 127.0.0.1 gaat:

client -> server  b'GET /books HTTP/1.1\r\nHost: books.test\r\n\r\n'  (41 bytes)
server -> client  b'HTTP/1.1 200 OK\r\ndate: ...\r\nserver: uvicorn\r\ncontent-length: 120\r\ncontent-type: application/json\r\n\r\n{"books":[{"id":1,"title":"Kindred","author":"Octavia E. Butler"},{"id":2,'...  (246 bytes)

De regel date bevat het tijdstip van jouw run, hier getoond als .... pl_http kort een lang antwoord in, maar wire.fetch las de hele body:

body: b'{"books":[{"id":1,"title":"Kindred","author":"Octavia E. Butler"},{"id":2,"title":"Caf\xc3\xa9 Society","author":"Ana Ruiz"}]}'  (120 bytes)

Er volgt geen spatie na een : of een ,. De json.dumps van je server zette na elk ervan een spatie, dus zijn body voor dezelfde twee boeken is 132 bytes.

Het tweede verzoek is HEAD /books, en de 405 uit les 2 komt over de lijn binnen:

client -> server  b'HEAD /books HTTP/1.1\r\nHost: books.test\r\n\r\n'  (42 bytes)
server -> client  b'HTTP/1.1 405 Method Not Allowed\r\ndate: ...\r\nserver: uvicorn\r\nallow: GET\r\ncontent-length: 31\r\ncontent-type: application/json\r\n\r\n'  (153 bytes)

De content-length van 31 is de grootte van de body van FastAPI voor deze fout, {"detail":"Method Not Allowed"}, en er volgt geen body: uvicorn stuurt er geen als antwoord op HEAD, de regel die je in les 4.5 met de hand schreef. Het derde verzoek vraagt om een boek dat niet bestaat:

client -> server  b'GET /books/99 HTTP/1.1\r\nHost: books.test\r\n\r\n'  (44 bytes)
server -> client  b'HTTP/1.1 404 Not Found\r\ndate: ...\r\nserver: uvicorn\r\ncontent-length: 25\r\ncontent-type: application/json\r\n\r\n{"detail":"no such book"}'  (157 bytes)

wire.fetch had voor dit alles niets nieuws nodig. Het las elke kop, vond content-length, en las precies zoveel bytes, of geen na HEAD: de framingregel uit hoofdstuk 9. Geen enkel antwoord zegt connection: close, dus onder /1.1 houdt uvicorn elke verbinding open voor een volgend verzoek, en de lengte is de enige manier waarop de client weet waar een body eindigt; wire.fetch sluit zijn kant zodra het de body heeft gelezen. Een client heeft alleen bytes nodig die HTTP volgen, welk programma ze ook schreef. De run eindigt zo:

--- uvicorn's log ---
(nothing)
--- result ---
uvicorn stopped on its own after 3 requests; the listening socket is closed
pl_http: every thread has stopped

Als een functie nog NotImplementedError opwerpt, krijgt het verzoek ervan HTTP/1.1 500 Internal Server Error, en het log van uvicorn noemt de , zoals error: Exception in ASGI application: NotImplementedError: not written yet: Lesson 1.

Wie welke regel schreef

Elke regel van de 404 kwam van een van drie plaatsen:

RegelGeschreven door
de status 404je functie, via HTTPException
Not Found en de rest van de statusregeluvicorn
date en server: uvicornuvicorn
content-type: application/json en content-length: 25FastAPI, dat het antwoord als codeerde en de bytes telde
de body {"detail":"no such book"}je functie koos de reden; FastAPI schreef de JSON

In de 405 koos FastAPI de status en schreef het ook allow: GET; je functie draaide niet. De headernamen zijn in kleine letters omdat de interface tussen de app en de server, ASGI, ze zo doorgeeft, dus Starlette, de toolkit waarop FastAPI is gebouwd, zet content-type, content-length en allow in kleine letters, en uvicorn schrijft zijn eigen regels date en server op dezelfde manier. http.server schreef Server en Date. Namen zijn niet hoofdlettergevoelig, dus allebei kloppen ze.

Er gebeurt nog iets buiten beeld. FastAPI draait een gewone def-functie zoals get_book op een werkthread, zodat een trage functie de server niet ophoudt terwijl ze wacht. Een functie die met async def is geschreven, zou in plaats daarvan één thread veel wachttijden laten overlappen; deze cursus houdt het bij gewone def, en hoofdstuk 13 noemt async HTTP als route om te volgen.

Welke regel voegde uvicorn toe, en niet je functie of FastAPI?

Je server stuurde 132 bodybytes voor dezelfde twee boeken; deze run toont er 120. Waarom?

Waarom eindigt deze run vanzelf?

Deze run is om naar te kijken, en niets ervan wordt beoordeeld. Les 5 maakt de app af met DELETE en de query limit. Daarna haalt hoofdstuk 12 je eigen server terug en verbindt het die met een client.