Why Modularise?
Consider what creating an employee actually involves:- Receiving the HTTP request
- Validating the incoming data
- Applying business rules (generate IDs, employee codes, timestamps)
- Saving the employee to the data store
- Returning the response
Project Structure
Step 1: Define the Models
Each layer works with data differently, so you define separate models for incoming requests, internal processing, and outgoing responses.app/models/employee.py
app/models/employee.py
Step 2: Repository Layer
The Repository bridges the Service and the data source. It hides the implementation details of how data is stored — whether in a dictionary, PostgreSQL, or MongoDB. For now it uses an in-memory dictionary. The Repository uses Constructor Injection — the data source is passed in from outside rather than created internally:app/database.py
app/database.py
app/repositories/employee_repository.py
app/repositories/employee_repository.py
Step 3: FastAPI Dependency Injection
Instead of manually creating the Repository in every endpoint, define a dependency provider function and let FastAPI call it automatically viaDepends():
app/dependencies.py
app/dependencies.py
Step 4: Service Layer
The Service contains the business logic. It receives the Repository through its constructor and transforms Request Models into Business Models.app/services/employee_service.py
app/services/employee_service.py
Step 5: Router (Controller) Layer
The Router is the entry point of every HTTP request. It validates inputs, delegates to the Service, and returns structured responses. It contains no business logic.app/routers/employee_router.py
app/routers/employee_router.py
app/main.py
app/main.py
Complete Request Flow
Benefits of This Architecture
This is the architecture used by most production FastAPI applications. Once you connect a real database in the next lesson, you’ll only need to modify the Repository layer — the Router and Service remain exactly the same.