Last checked
Train the model and save it with joblib. Write a FastAPI app that loads the file once and exposes a POST route with a validated input. Run it with uvicorn, test it with curl, then copy the app, model and a requirements file into a Docker image and start it with uvicorn.
McTaba runs coding and data bootcamps in Kenya. This guide is written to be useful whether or not you ever join one.
A model in a notebook helps nobody. The shop app, the M-Pesa callback or the WhatsApp bot cannot open your notebook. They can call a URL and read a reply. An API is that URL. This is a skills step on our data science career map.
We use a small payment risk example. The training data is made up and the rule behind it is invented, so this model is for learning only. You need pip install scikit-learn joblib fastapi uvicorn.
import joblib
import numpy as np
from sklearn.ensemble import RandomForestClassifier
rng = np.random.default_rng(0)
amount = rng.uniform(100, 100000, 3000)
hour = rng.integers(0, 24, 3000)
risky = ((amount > 60000) & ((hour < 5) | (hour > 22))).astype(int)
model = RandomForestClassifier(n_estimators=50, random_state=0)
model.fit(np.c_[amount / 1000, hour], risky)
joblib.dump(model, "model.joblib")
Save as train.py and run it. You now have model.joblib. Note the feature order: amount in thousands, then hour. The API must send features in the same order.
| File | Job |
|---|---|
| train.py | Fits the model and saves it |
| model.joblib | The saved model |
| app.py | The FastAPI app that loads and serves it |
| requirements.txt | The libraries, pinned to the versions you trained with |
| Dockerfile | How to package it all |
Serving models with FastAPI, Docker and MLflow is phase 6 of our Data Science to AI Engineering programme.
import joblib
from fastapi import FastAPI
from pydantic import BaseModel, Field
app = FastAPI(title="Payment risk API")
model = joblib.load("model.joblib")
class Payment(BaseModel):
amount_kes: float = Field(gt=0)
hour: int = Field(ge=0, le=23)
@app.post("/predict")
def predict(p: Payment):
prob = model.predict_proba([[p.amount_kes / 1000, p.hour]])[0][1]
return {"risk": round(float(prob), 3), "review": bool(prob >= 0.5)}
Two things matter here. The model loads once when the app starts, not on every request. And the Payment class checks input before it reaches the model, so an hour of 30 or a negative amount gets a clear error and not a crash.
Start it with uvicorn app:app --port 8000. FastAPI also builds a test page for free at http://localhost:8000/docs.
Get weekly developer tips
Join 25,000+ developers. Practical guides, job tips, and new content — straight to your inbox.
No spam. Unsubscribe anytime.
curl -X POST http://localhost:8000/predict \
-H "Content-Type: application/json" \
-d '{"amount_kes": 85000, "hour": 2}'
For example, a large amount at 2 AM should come back with a high risk and review set to true. Try KES 500 at 2 PM and you should see a risk near zero. Then send {"amount_kes": -5, "hour": 30}: you get a 422 reply that names the two bad fields.
Write these three calls down as a test file before you change anything. A model API that quietly changes its answers is harder to fix than one that breaks loudly.
Create requirements.txt from the environment you trained in: pip freeze | grep -iE "fastapi|uvicorn|scikit-learn|joblib|pydantic". A model saved with one scikit-learn version can fail or change behaviour under another, so pin the versions.
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py model.joblib ./
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
Build and run: docker build -t risk-api . then docker run -p 8000:8000 risk-api. The curl call from step 3 now hits the container. The FastAPI Docker documentation (checked on 3 November 2026) copies the requirements file first so Docker can reuse its cached layer, and says to use the list form of CMD so the app shuts down cleanly. We follow both.
/health route so a host can check the app is alive.To train something worth serving, try mobile money fraud detection with machine learning. To refresh a model's data every day, see building a pipeline with Airflow and Docker. New to Python? Begin with Python for data science for beginners.
If you want this built for your business, as a WhatsApp reply or a payment check, see our AI agents service. To learn the whole path with mentors, read about the Data Science to AI Engineering programme: 5 months full time or 8 months part time, KES 140,000, next intake 11 January 2027.
KES 140,000
Data Science to AI Engineering: 5 months full time or 8 months part time, hybrid in Nairobi. Fraud, credit and M-Pesa data from Week 1, and every model deployed. Starts 11 January 2027.
See the Data Science programme