FastAPI MVC CRUD Build Data Models and Controllers

Learning Objective: By the end of this lesson, you will be able to create mock data models for a FastAPI application and build a basic controller to serve that data through an API.

Introduction

In this lesson, you’ll learn how to define mock data models and create the controller that will handle API requests in your FastAPI app. We’ll be building a simple app that mimics the functionality of an inventory system for teas. While we’re not working with a real database, this approach will let us focus on the fundamental concepts of building a FastAPI CRUD app.

In the context of MVC (Model-View-Controller) architecture:

By creating and structuring your app this way, you’ll be able to scale and replace the mock data with a real database later on without disrupting the flow of your application.

Define your mock data model

Before we build the controller, we’ll start by defining some mock data to simulate what we would typically store in a database. In the models/tea_data.py file, we will create a Python dictionary that holds a list of tea objects.

Why use mock data?

We’ll use mock data for the following reasons:

Here’s what your models/tea_data.py file should look like:

# tea_data.py

teas_db = {
    "teas": [
        {"id": 1, "name": "chai", "in_stock": True, "rating": 4.2},
        {"id": 2, "name": "lemongrass", "in_stock": True, "rating": 3.8},
        {"id": 3, "name": "matcha", "in_stock": False, "rating": 4.4},
    ]
}

This mock data will represent our “database,” and it contains a list of tea objects. Each tea object has:

Create the controller

Next, we’ll create a controller in the controllers/teas.py file. The controller is responsible for handling requests, interacting with the model (in this case, tea_data.py), and returning the appropriate responses.

In FastAPI, the controller is implemented using routers. A router groups related endpoints together.

For this application, we will follow this route structure in our teas controller:

HTTP Method Endpoint Description
GET /teas/ Retrieve all teas.
GET /teas/{tea_id} Retrieve an existing tea by ID.
POST /teas/ Add a new tea.
PUT /teas/{tea_id} Update an existing tea by ID.
DELETE /teas/{tea_id} Delete a tea by ID.

Create an index route to GET all /teas/

Open controllers/teas.py in your editor and add the following code:

# teas.py

from fastapi import APIRouter
from models.tea_data import teas_db

router = APIRouter()

@router.get("/teas")
def get_teas():
    # Retrieve all teas
    return teas_db

Let’s review this code together:

  1. We first create an instance of APIRouter and assign it to the router variable. This is where we will define our API endpoints related to teas.

    router = APIRouter()
    
  2. The @router.get("/teas") line tells FastAPI that we want to define a GET endpoint for /teas. This means that when a user sends a GET request to /teas, the get_teas function will be called.

    @router.get("/teas")
    def get_teas():
        # Retrieve all teas
        return teas_db
    
  3. The get_teas function will return the data from teas_db, which contains all the mock tea data. Since FastAPI automatically converts the data to JSON format, this will be returned as a JSON response to the client.