A FastAPI template for info2602 students based on the fullstack fastapi template with a few modifications to make it a layered architecture that combines the best of MVC and service repository pattern. This codebase is structured to reduce the repeatibility of code (the DRY principle) as it was demonstrated in class that code is usually repeated when implementing functionality for a CLI app, a headless API, and a fullstack app. When writing software at scale, deduplicating code is important as it makes the codebase easier to maintain, test and scale.
Additionally, this codebase follows an API-first, modern AJAX flow (similar to Lab 8). In essence, this can be summarized as follows.
- If we want to have this backend web application render the UI as well, we can implement our VIEWS that return our user interface.
- A small javascript script (
utils.js) intercepts default form submissions and instead sends an appropriate endpoint to our api endpoints
The main advantage of this application structure are plenty:
- We don't have to implement a jinja based frontend for the application. We can simply implement api endpoints like we did in labs 1-4
- We can implement a backend API for a mobile / desktop application (where the view logic resides in java/kotlin/flutter etc)
- We can implement a backend API that uses a separate frontend like Vue, React, Next, Nuxt etc.
- We can export the list of endpoints and have other services (like AI agents) consume them
- We can implement an app that functions purely from the CLI
The MVC pattern is a code pattern that is used to organise the modules of a project and when applied to a project, it usually works as follows:
- Models are your SQLModel/SQLAlchemy classes (The classes that become database tables)
- Controllers are utility functions used to mutate models and/or perform business logic
- Views bind controllers to http routes passing along any user parameters from the request to the controller
The Service Repository pattern is designed to keep business logic separate from the data access and it aims to separate the codebase into distinct layers.
- The Repository Layer acts as a mediator between the application and the data source (the database, files, etc)
- The Service Layer sits between the controller and the repository and this is where business logic lives.
The job of the repository layer is to handle CRUD operations on a model. It doesn't care about the rules at the business logic layer, it's only concerned about how to get and manipulate data.
The job of the service layer is to handle the RULES of the application. This is where the business logic comes in such as checking to see if a user's authorized to access the data.
This app is structuresd as follows
FastAPIStarter |-- app | |- api | |- dependencies | |- models | |- repositories | |- schemas | |- services | |- static | |- templates | |- utilities | |- views |-- tests/ |-- env.example |-- pyptoject.toml |-- README.md
app This folder contains all of our application code.
tests This contains the tests (unit tests, integration tests, etc) for the application.
api This folder contains the endpoints (route fucntions) of our app.
dependencies This folder contains the functions that we'd usually use for dependency injection e.g. getting the information of the user who's performing the request, getting a reference to the database, etc
models This folder contains the Pydantic / SQLModel / SQLAlchemy models that eventually become database tables. Note that the files in here are strictly those that become database tables. The other models used for request and response validation go in the schemas folder
repositories files in this folder are used to query the datastore, which depending on the app can be a file, database, another api, etc. Usually though, it's our database.
services The business logic of the application lives here.
schemas files in this folder specify pydantic / sqlmodel classes that are used for data validation only and NOT models that become database tables.
utilities This contain generic helper functions
static this contains folders that contain css, js, img and other assets we may need when this app is responsible for rendering of the frontend UI>
templates this contains our jinja2 templates
views this contains the route functions used for when this app is responsible for rendering the frontnend UI
Note that the file env.example provides a default set of configuration values for this application. you MUST create a copy of this file named
.envbefore launching the app. The preconfigured environment allows a user to have an app that uses a sqlite database for a datastore as well as some other default configurations. The values in this should ideally be modified for production. For more possible variables, check out theconfig.pyfile
If you so ever choose to use this template for your own projects, please consider the following:
- You WILL need to modify the default configuration to
- Use a database that's more suitable for production.
- Change the default secret
- Change the default environment
- You may need to tweak additional settings in the
config.pyfile for scalability - You'd need to look into a database migration / upgrade tool like alembic
- You may want to dockerize the application for easier deployment
- You may want to switch from storing cookies in localstorage to only cookies depending on your security needs.