A scikit-learn model becomes easier to test from other applications when it responds through an HTTP endpoint instead of a Python prompt. Serving the persisted estimator with FastAPI gives frontend code, workers, and integration tests a small JSON scoring interface around the same prediction object.
The app loads a trusted joblib artifact at startup, validates each request with a Pydantic model, and returns a named prediction from the Iris classifier. FastAPI handles the request body and response serialization, while Uvicorn runs the local ASGI server.
Use the joblib loading pattern only for artifacts from a trusted training environment, because pickle-based persistence can execute code while loading and requires matching package versions. For untrusted artifacts or non-Python serving targets, prefer a safer persistence path such as skops.io or ONNX.
Steps to serve a scikit-learn model with FastAPI:
- Create an isolated Python environment for the API project.
$ python3 -m venv .venv
- Install scikit-learn, joblib, FastAPI, and Uvicorn in the environment.
$ .venv/bin/python -m pip install --upgrade pip scikit-learn joblib fastapi "uvicorn[standard]"
The quoted uvicorn[standard] extra installs the recommended server dependencies without relying on shell-specific bracket handling.
- Create train_model.py in the project directory.
- train_model.py
from joblib import dump from sklearn.datasets import load_iris from sklearn.linear_model import LogisticRegression from sklearn.pipeline import make_pipeline from sklearn.preprocessing import StandardScaler iris = load_iris() model = make_pipeline( StandardScaler(), LogisticRegression(max_iter=200, random_state=0), ) model.fit(iris.data, iris.target) dump( { "model": model, "target_names": iris.target_names.tolist(), }, "iris_model.joblib", ) print("saved iris_model.joblib") print("classes: setosa, versicolor, virginica")
The pipeline keeps scaling and classification together so the API uses the same preprocessing path during prediction.
- Run the training script to write the model artifact.
$ .venv/bin/python train_model.py saved iris_model.joblib classes: setosa, versicolor, virginica
- Create main.py beside the model artifact.
- main.py
from fastapi import FastAPI from joblib import load from pydantic import BaseModel, Field artifact = load("iris_model.joblib") model = artifact["model"] target_names = artifact["target_names"] app = FastAPI(title="Iris model API") class PredictionRequest(BaseModel): features: list[float] = Field(..., min_length=4, max_length=4) class PredictionResponse(BaseModel): prediction: str @app.get("/health") def health() -> dict[str, str]: return {"status": "ok"} @app.post("/predict", response_model=PredictionResponse) def predict(request: PredictionRequest) -> PredictionResponse: predicted_class = int(model.predict([request.features])[0]) return PredictionResponse(prediction=target_names[predicted_class])
Load only model files created by a trusted training process. joblib uses pickle-based loading, so a malicious artifact can run code during import.
- Start the local FastAPI server with Uvicorn.
$ .venv/bin/uvicorn main:app --host 127.0.0.1 --port 8000 INFO: Started server process [12345] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
Keep this terminal open while testing the endpoint.
- Check the health endpoint from another terminal.
$ curl --silent http://127.0.0.1:8000/health {"status":"ok"} - Send a JSON feature vector to the prediction endpoint.
$ curl --silent --request POST http://127.0.0.1:8000/predict \ --header 'Content-Type: application/json' \ --data '{"features":[5.1,3.5,1.4,0.2]}' {"prediction":"setosa"}The four numbers match the Iris feature order: sepal length, sepal width, petal length, and petal width.
- Stop the local server with Ctrl+C after the smoke test.
^C INFO: Shutting down INFO: Waiting for application shutdown. INFO: Application shutdown complete. INFO: Finished server process [12345]
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.