6 · A FastAPI prediction endpoint
A model only becomes a service when something can call it over HTTP. FastAPI turns your loaded `.joblib` into a `/predict` endpoint with a typed request schema — and validating the incoming features before predicting is what separates a robust API from a fragile one.
FastAPI wraps your loaded model in an HTTP `/predict` endpoint: a Pydantic request model TYPE-CHECKS the incoming JSON, the model is loaded ONCE at startup (not per request), and you VALIDATE the feature vector (right length, finite, in range) BEFORE calling `model.predict` — turning garbage input into a clear error instead of a wrong prediction.
Without this:
Without a serving layer your model can't be called by anything; without input validation, a malformed request either crashes the worker or — worse — silently returns a confident, meaningless prediction.
You have a reproducible .joblib artifact and you can package it in Docker. But a model in a file still can't do anything for a user — something has to call it. The standard way is to expose it over HTTP as a web service, and the modern Python tool for that is FastAPI.
FastAPI gives you three things that matter for model serving:
1. A typed request schema (Pydantic). You declare the shape of the incoming request as a Python class. Pydantic then automatically rejects any request that doesn't match — wrong types, missing fields — before your code ever runs, returning a clear 422 error and even auto-generating OpenAPI docs. A request like {"features": [1.2, -0.4]} is validated against your schema for free.
2. Load the model ONCE at startup. You load the .joblib when the app boots — not on every request. Loading is slow (reading and deserializing the file); requests must be fast. So the model becomes a module-level object the request handler reuses. Loading per-request would make every prediction sluggish and waste memory.
3. A /predict route. A function decorated with @app.post("/predict") receives the validated request, runs the model, and returns JSON. This is the actual prediction endpoint clients hit.
But typed JSON is not enough — validate the FEATURES too. Pydantic checks that features is a list of numbers. It does not know your model expects exactly, say, 4 features, or that they must be finite and within a sane range. A request with the wrong number of features, or with NaN/inf, or a wildly out-of-range value, will sail past Pydantic and hit model.predict — where it either throws a cryptic shape error or, worse, returns a confident but meaningless prediction. So before calling model.predict, you explicitly check: correct length, all finite, within expected bounds — and raise a clear error if not. The runnable cell below implements exactly this validation gate on a toy loaded model, showing a valid request succeeding and an invalid one being rejected cleanly.
The FastAPI app itself doesn't run in the browser (it needs a server), so it's read-along; the pure prediction-and-validation logic is runnable below.
A FastAPI `app.py`: load the joblib model once at startup, a Pydantic request/response schema, and a `/predict` route that validates the feature vector before calling the model.
Python (in browser)
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Why does a typed request schema (Pydantic) matter for a model-serving API?
- FastAPI exposes the model over HTTP: a Pydantic request schema type-checks the JSON, and a `/predict` route runs the model and returns JSON.
- Load the `.joblib` model ONCE at startup as a module-level object, never per request — loading is slow and requests must be fast.
- Pydantic guards the JSON shape, but YOU must validate the feature vector (length, finite, in range) right before `model.predict` — or risk a crash or a confident garbage prediction.
Nearly every online ML model is served behind a FastAPI (or similar) `/predict` endpoint with a typed schema and an input-validation gate — it's the standard shape of a real-time inference service.
If you remove it: Your model would stay an un-callable file, or you'd serve it with no input checks — letting malformed requests crash workers or extract silent, meaningless predictions.