In this blog post, we are going to build a simple Employee Management System using FastAPI and Pydantic. FastAPI is a modern, fast (high-performance), web framework for building APIs with Python based on standard Python type hints. Pydantic is a data validation and settings management using Python type annotations.
GitHub project: FastAPI Employee Management Application
Our application will be organized as a Python package called employee with five different files: utils.py, schemas.py, openapi.py, api.py, and main.py.
In utils.py, we define a utility function that returns the current date and time in UTC format:
from datetime import UTC, datetime
def utcnow() -> datetime:
return datetime.now(tz=UTC)
In schemas.py, we use Pydantic to define our data models. We have EmployeeCreatePayload for the data coming into our application and EmployeeCreated for the data going out of our application.
import uuid
from datetime import datetime
from pydantic import BaseModel, Extra, Field, PositiveFloat, UUID4
from .utils import utcnow
class EmployeeCreatePayload(BaseModel):
name: str
position: str
salary: PositiveFloat
class Config:
extra = Extra.forbid
class EmployeeCreated(BaseModel):
id: UUID4 = Field(default_factory=uuid.uuid4)
name: str
position: str
salary: float
created_at: datetime = Field(default_factory=utcnow)
In openapi.py, we use FastAPI's in-built support for OpenAPI to define our response types:
from typing import Any, TypeAlias
from fastapi import status
from pydantic import BaseModel
OpenAPIResponseType: TypeAlias = dict[int | str, dict[str, Any]]
class ErrorModel(BaseModel):
detail: str
EMPLOYEE_NOT_FOUND: OpenAPIResponseType = {
status.HTTP_404_NOT_FOUND: {
"model": ErrorModel,
"content": {
"application/json": {
"examples": {
status.HTTP_404_NOT_FOUND: {
"summary": "Employee not found",
"value": {
"detail": "No employee found with the provided ID:"
" '7c926000-613b-468e-a17d-a3fa1e3ef0e8'."
},
},
},
},
},
},
}
In api.py, we define our API endpoints using FastAPI's APIRouter. We have endpoints for creating an employee, retrieving a list of all employees, retrieving a specific employee by ID, and deleting all employees.
from fastapi import APIRouter, HTTPException, status
from pydantic import UUID4
from employee import schemas
from employee.openapi import EMPLOYEE_NOT_FOUND
router = APIRouter(prefix="/employees", tags=["employees"])
EMPLOYEES = {}
@router.post(path="", status_code=status.HTTP_201_CREATED)
def create_employee_endpoint(
payload: schemas.EmployeeCreatePayload,
) -> schemas.EmployeeCreated:
new_employee = schemas.EmployeeCreated(
name=payload.name,
position=payload.position,
salary=payload.salary,
)
EMPLOYEES[new_employee.id] = new_employee
return new_employee
@router.get(path="")
def list_employees_endpoint() -> list[schemas.EmployeeCreated]:
return list(EMPLOYEES.values())
@router.delete(path="", status_code=status.HTTP_204_NO_CONTENT)
def clear_all_employees_endpoint() -> None:
EMPLOYEES.clear()
@router.get(path="/{employee_id}", responses=EMPLOYEE_NOT_FOUND)
def retrieve_employee_endpoint(employee_id: UUID4) -> schemas.EmployeeCreated:
try:
return EMPLOYEES[employee_id]
except KeyError:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"No employee found with the provided ID: '{employee_id}'.",
)
Finally, in main.py, we create our FastAPI application and include the router from api.py:
from fastapi import FastAPI
from employee.api import router
app = FastAPI()
app.include_router(router=router)
To run this project, you need Python 3.11 or higher. Clone the repository, navigate to the repo directory, and install the project using Poetry. You can then run the application with the command uvicorn main:app --app-dir employee --reload.
To interact with the API, open your browser and visit http://127.0.0.1:8000/docs
That's it! You've built a simple Employee Management System using FastAPI and Pydantic. This example should give you a good idea of how to structure your FastAPI projects and how to use Pydantic for data validation and serialization. Happy coding!
In addition to the Employee Management System, the repository also includes a suite of tests to verify the functionality of the API. It's always a good practice to write tests for your code to ensure it's behaving as expected and to catch any issues or bugs early in the development process.
Moreover, the repository includes a detailed README.md file. This file provides all the necessary information about the project, including the project structure, installation and usage instructions, and a description of the available API endpoints.
We strongly encourage you to read the README.md file in the repository and to run the tests to get a better understanding of the application and to ensure everything is working correctly. Happy learning and coding!