Create a REST API for Predictions

Learn to create a REST API for predictions in this Applied AI engineering tutorial. Step-by-step, practical, with troubleshooting.

Focus: create a rest api for predictions

Sponsored

You've trained a model that predicts house prices with impressive accuracy — but right now it only works on your laptop, hidden inside a Jupyter notebook. Your stakeholders can't use it, your app can't call it, and your hard work is effectively invisible. The missing piece is a REST API for predictions: a simple, standardized way to expose your model so any client — a web app, a mobile app, or a command-line script — can send data and get predictions back. This lesson walks you through turning your model into a production-ready API, step by step, using Python and FastAPI.

The problem this lesson solves

Machine learning models are powerful only when they're accessible. Without an API, every prediction requires someone to run your code manually, which is slow, error-prone, and impossible for non-technical users. You might think, "Why not just save the model and load it in the app?" That works for a single script, but real-world apps need to handle multiple requests, manage authentication, and scale under load. A REST API for predictions solves these problems by:

  • Standardizing access — any client that can make an HTTP request can get predictions.
  • Decoupling model and application — the model lives as its own service, so you can update it without touching the frontend.
  • Enabling concurrent users — your API can handle many requests at once, not just one.
  • Making the model testable — you can write integration tests against the API endpoint, which is far simpler than testing the model in isolation.

The pain is real: without an API, your model is a demo, not a product.

Core concept / mental model

Think of your ML model as a function: input goes in, a prediction comes out. A REST API for predictions wraps that function in a web server. The client sends a request with JSON data, the server runs your model, and sends back a response with the predicted value. It's a stateless contract: each request is independent, and the server doesn't remember past calls.

Here's the mental model in three layers:

  1. Client — who asks for predictions (could be a browser, a mobile app, or another service).
  2. API server — the middleware that receives requests, validates input, and calls the model.
  3. Model — the brain that converts raw features into a prediction.

The beauty of this separation is you can replace the model with a new version without changing the client — as long as the API contract stays the same. You can also add features like caching, rate limiting, or authentication without touching the model code.

How it works step by step

Building a REST API for predictions is a repeatable four-step process. Let's break it down.

Step 1: Serialize your model

Your trained model lives in memory as a Python object. Before it can be served by an API, you need to save it to disk. Tools like pickle or joblib are common for scikit-learn models. This step makes your model portable and reloadable.

Step 2: Choose a web framework

You need a Python web framework to handle HTTP requests. The most popular choices are Flask (lightweight, easy to learn) and FastAPI (modern, fast, with automatic API docs). FastAPI is often preferred for AI APIs because of its built-in validation and OpenAPI support.

Step 3: Define your endpoint(s)

An endpoint is a URL like /predict that accepts POST requests. The client sends a JSON body with the input features. Your API code deserializes that JSON into a Python dict, passes it to the model's predict() method, and returns the result as JSON.

Step 4: Run and test

Start your server (e.g., with uvicorn for FastAPI), then send a test request using curl or Python's requests library. Verify the response contains the prediction you expect. Then you can hook it into your application.

That's the core loop. The next section puts it into practice.

Hands-on walkthrough

Let's create an actual REST API for a linear regression model that predicts house prices. We'll use FastAPI because it's modern and beginner-friendly, but the same concepts apply to Flask.

Prerequisites

Ensure you have the required packages installed:

pip install fastapi uvicorn scikit-learn numpy joblib

Train and save a simple model

First, we'll train a tiny model on synthetic data and save it. This step simulates what you'd do in your own workflow.

# train_model.py
import numpy as np
from sklearn.linear_model import LinearRegression
from joblib import dump

# Synthetic data: house size -> price
X = np.array([[1000], [1500], [2000], [2500], [3000]])
y = np.array([200000, 300000, 400000, 500000, 600000])

model = LinearRegression()
model.fit(X, y)

# Save model to disk
with open('house_price_model.joblib', 'wb') as f:
    dump(model, f)

print("Model trained and saved!")

Build the FastAPI app

Next, we create the API server that loads the model and exposes a prediction endpoint.

# api.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from joblib import load
import numpy as np

# Load the model once at startup
model = load('house_price_model.joblib')

app = FastAPI()

# Define the request schema: we expect a 'size' field
class PredictionRequest(BaseModel):
    size: float

# Define the response schema
class PredictionResponse(BaseModel):
    predicted_price: float

@app.get("/")
def read_root():
    return {"message": "Welcome to the house price predictor! Go to /docs for API docs."}

@app.post("/predict", response_model=PredictionResponse)
def predict_price(request: PredictionRequest):
    try:
        # Convert input to numpy array and predict
        features = np.array([[request.size]])
        prediction = model.predict(features)[0]
        return PredictionResponse(predicted_price=prediction)
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

Run the server

Start the server with uvicorn:

uvicorn api:app --reload

You should see output similar to:

INFO:     Uvicorn running on http://127.0.0.1:8000
INFO:     Started reloader process [12345]
INFO:     Started server process [12345]

Send a test request

Open a new terminal and use curl to send a POST request with JSON data:

curl -X POST "http://127.0.0.1:8000/predict" -H "Content-Type: application/json" -d '{"size": 1800}'

Expected response (your exact numbers may vary slightly):

{"predicted_price": 360000.0}

You can also open your browser at http://127.0.0.1:8000/docs — FastAPI gives you interactive docs where you can try the endpoint directly.

That's it! You've created a REST API for predictions.

Compare options / when to choose what

Not all API frameworks are the same. Here's a quick comparison to help you choose:

Framework Performance Setup ease Built-in validation Best for
FastAPI Fast (async) Moderate Yes (Pydantic) Modern AI services, production-ready
Flask Slower (synchronous) Easy No (manual) Quick prototypes, simple internal tools
Django REST Moderate Hard (batteries included) Yes Large web apps with databases

When to choose FastAPI — you value speed, type safety, and automatic API documentation. It's the go-to for most AI engineers.

When to choose Flask — you need a minimal setup and already know Flask; good for learning HTTP basics.

When to choose Django REST — you're embedding the API in a larger web app with user accounts and a database.

Variations to consider:

  • Model versioning — Add a version to your endpoint (e.g., /v1/predict) so breaking changes don't break old clients.
  • Batch prediction — Accept a list of inputs and return a list of predictions to reduce overhead.
  • Authentication — Add API keys (requires fastapi-security or similar) for production deployments.

Troubleshooting & edge cases

Common issues when building a REST API for predictions:

CORS errors in a web app

If your frontend calls the API and gets a CORS error, add the CORSMiddleware to your app:

from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # restrict this in production!
    allow_methods=["*"],
    allow_headers=["*"],
)

Input validation errors

Your API returns a 422 error when the client sends wrong types. Use Pydantic's BaseModel to define fields with types and constraints (e.g., size: float = Field(gt=0)) to give friendly error messages.

Model loading failures

If the model file isn't found or the serialization format is wrong, your server crashes. Use absolute paths or environment variables, and test loading the model in a separate script before starting the API.

Handling missing features

What if the client omits a field? With Pydantic, the request will be rejected with a 422. To make a field optional, set a default (e.g., size: float = 0.0), but be careful — this can silently produce wrong predictions.

What you learned & what's next

You now know the core idea behind creating a REST API for predictions: you serialize your model, wrap it in a web framework, and define endpoints that accept JSON input and return JSON output. You completed a hands-on exercise that built a working API with FastAPI, trained a model, saved it, and served predictions via a /predict endpoint. You also compared FastAPI, Flask, and Django REST, and learned common troubleshooting patterns like CORS and validation errors.

In the next lesson, you'll learn how to deploy this API to production — including how to containerize it with Docker and deploy it to a cloud platform like Heroku or AWS. You'll also explore authentication and scaling techniques to handle real-world traffic. To prepare, try adding batch prediction support to the API you built, and test it with multiple inputs in one request.

Practice recap

Now it's your turn: modify the API to accept a list of house sizes and return multiple predictions. Change the request schema to sizes: List[float] and loop through them. Run the server and test with a JSON array like {"sizes": [1500, 2500]}. See if you can also add a /predict_one endpoint using the same model.

Common mistakes

  • Forgetting to load the model once at startup — reload it inside each request is slow and inefficient.
  • Not validating input with Pydantic, leading to cryptic errors or wrong predictions from malformed JSON.
  • Sending an array where a single value is expected, or vice versa, causing shape mismatch errors in NumPy.
  • Ignoring CORS errors and wondering why the frontend can't call the API from the browser.

Variations

  1. Use Flask instead of FastAPI: it's simpler but lacks automatic validation and async support. The code is similar but you handle JSON manually.
  2. Add model versioning in the URL, e.g., /v1/predict and /v2/predict, so upgrades don't break existing clients.
  3. Support batch predictions: accept a list of objects and return a list of results, reducing network round trips.

Real-world use cases

  • A real-estate startup exposes a house price predictor API that their web app calls in real-time to show estimates to users.
  • An e-commerce company runs a churn prediction API that a marketing automation tool calls to segment customers.
  • A healthcare analytics firm deploys a disease-risk model as a REST API so doctors can query it from their existing EHR system.

Key takeaways

  • A REST API wraps your model in a web server, decoupling it from any client.
  • Serialization (e.g., with joblib) makes your trained model portable and loadable in a web app.
  • FastAPI provides automatic request validation, async performance, and interactive docs — ideal for AI APIs.
  • The call flow is: client sends JSON → server validates → model predicts → JSON response.
  • Always test your API with curl or a client before hooking it into an app.
  • Handle errors with HTTPException and think about CORS for browser-based clients.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.