First Commit - API Tested and functional
This commit is contained in:
BIN
src/__pycache__/main.cpython-312.pyc
Normal file
BIN
src/__pycache__/main.cpython-312.pyc
Normal file
Binary file not shown.
BIN
src/__pycache__/main.cpython-314.pyc
Normal file
BIN
src/__pycache__/main.cpython-314.pyc
Normal file
Binary file not shown.
BIN
src/application/__pycache__/exceptions.cpython-312.pyc
Normal file
BIN
src/application/__pycache__/exceptions.cpython-312.pyc
Normal file
Binary file not shown.
BIN
src/application/__pycache__/exceptions.cpython-314.pyc
Normal file
BIN
src/application/__pycache__/exceptions.cpython-314.pyc
Normal file
Binary file not shown.
2
src/application/exceptions.py
Normal file
2
src/application/exceptions.py
Normal file
@@ -0,0 +1,2 @@
|
||||
class UserAlreadyExists(Exception):
|
||||
pass
|
||||
Binary file not shown.
Binary file not shown.
13
src/application/ports/user_repository.py
Normal file
13
src/application/ports/user_repository.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from domain.users import User
|
||||
|
||||
class UserRepository(ABC):
|
||||
@abstractmethod
|
||||
def save(self, user: User):
|
||||
...
|
||||
@abstractmethod
|
||||
def viewAll(self) -> list[User]:
|
||||
...
|
||||
@abstractmethod
|
||||
def viewById(self, user_id:int):
|
||||
...
|
||||
BIN
src/application/services/__pycache__/create_user.cpython-312.pyc
Normal file
BIN
src/application/services/__pycache__/create_user.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
33
src/application/services/user_services.py
Normal file
33
src/application/services/user_services.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from domain.users import User
|
||||
from application.ports.user_repository import UserRepository
|
||||
|
||||
class CreateUser:
|
||||
def __init__(self, repo: UserRepository):
|
||||
if not isinstance(repo, UserRepository):
|
||||
raise TypeError("repo must implement UserRepository")
|
||||
self.repo = repo
|
||||
|
||||
def execute(self, name:str, email:str, phone:str):
|
||||
user = User(user_id=0, email=email, name=name, phone=phone)
|
||||
self.repo.save(user)
|
||||
return user
|
||||
|
||||
class ViewUsers:
|
||||
def __init__(self, repo: UserRepository):
|
||||
if not isinstance(repo, UserRepository):
|
||||
raise TypeError("repo must implement UserRepository")
|
||||
self.repo = repo
|
||||
|
||||
def execute(self):
|
||||
users = self.repo.viewAll()
|
||||
return users
|
||||
|
||||
class ViewUserById:
|
||||
def __init__(self, repo: UserRepository):
|
||||
if not isinstance(repo, UserRepository):
|
||||
raise TypeError("repo must implement UserRepository")
|
||||
self.repo = repo
|
||||
|
||||
def execute(self, user_id: int) -> User | None:
|
||||
user = self.repo.viewById(user_id)
|
||||
return user
|
||||
BIN
src/domain/__pycache__/users.cpython-312.pyc
Normal file
BIN
src/domain/__pycache__/users.cpython-312.pyc
Normal file
Binary file not shown.
BIN
src/domain/__pycache__/users.cpython-314.pyc
Normal file
BIN
src/domain/__pycache__/users.cpython-314.pyc
Normal file
Binary file not shown.
8
src/domain/users.py
Normal file
8
src/domain/users.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class User:
|
||||
user_id: int
|
||||
name: str
|
||||
email: str
|
||||
phone: str
|
||||
5
src/infrastructure/adapters/persistence/__init__.py
Normal file
5
src/infrastructure/adapters/persistence/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
from infrastructure.adapters.persistence.db import engine
|
||||
from infrastructure.adapters.persistence.models import Base
|
||||
|
||||
Base.metadata.create_all(bind=engine)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
17
src/infrastructure/adapters/persistence/db.py
Normal file
17
src/infrastructure/adapters/persistence/db.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker, declarative_base
|
||||
|
||||
DATABASE_URL = "sqlite:///./users.db"
|
||||
|
||||
engine = create_engine(
|
||||
DATABASE_URL,
|
||||
connect_args={"check_same_thread": False}
|
||||
)
|
||||
|
||||
SessionLocal = sessionmaker(
|
||||
bind=engine,
|
||||
autocommit=False,
|
||||
autoflush=False
|
||||
)
|
||||
|
||||
Base = declarative_base()
|
||||
10
src/infrastructure/adapters/persistence/models.py
Normal file
10
src/infrastructure/adapters/persistence/models.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from sqlalchemy import Column, Integer, String
|
||||
from infrastructure.adapters.persistence.db import Base
|
||||
|
||||
class UserModel(Base):
|
||||
__tablename__ = "users"
|
||||
|
||||
user_id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String, unique=False, index=True)
|
||||
email = Column(String, unique=True, index=True)
|
||||
phone = Column(String, unique=True, index=True)
|
||||
@@ -0,0 +1,61 @@
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from domain.users import User
|
||||
from application.ports.user_repository import UserRepository
|
||||
from infrastructure.adapters.persistence.db import SessionLocal
|
||||
from infrastructure.adapters.persistence.models import UserModel
|
||||
from application.exceptions import UserAlreadyExists
|
||||
|
||||
class SqlUserRepository(UserRepository):
|
||||
def __init__(self):
|
||||
self.db: Session = SessionLocal()
|
||||
|
||||
def save(self, user: User):
|
||||
model = UserModel(
|
||||
name= user.name,
|
||||
email=user.email,
|
||||
phone=user.phone
|
||||
)
|
||||
|
||||
self.db.add(model)
|
||||
|
||||
try:
|
||||
self.db.commit()
|
||||
except IntegrityError:
|
||||
self.db.rollback()
|
||||
raise UserAlreadyExists("A user with the same phone number or name does already exist.")
|
||||
|
||||
|
||||
self.db.refresh(model)
|
||||
|
||||
return User(
|
||||
user_id = model.user_id,
|
||||
name = model.name,
|
||||
email = model.email,
|
||||
phone = model.phone
|
||||
)
|
||||
|
||||
def viewAll(self) -> list[User]:
|
||||
models = self.db.query(UserModel).all()
|
||||
|
||||
return [
|
||||
User(
|
||||
user_id=model.user_id,
|
||||
name = model.name,
|
||||
email = model.email,
|
||||
phone = model.phone
|
||||
) for model in models
|
||||
]
|
||||
|
||||
def viewById(self, user_id: int) -> User | None:
|
||||
model = self.db.query(UserModel).filter(UserModel.user_id == user_id).first()
|
||||
|
||||
if not model:
|
||||
return None
|
||||
|
||||
return User(
|
||||
user_id=model.user_id,
|
||||
name = model.name,
|
||||
email = model.email,
|
||||
phone = model.phone
|
||||
)
|
||||
BIN
src/infrastructure/api/users/__pycache__/app.cpython-312.pyc
Normal file
BIN
src/infrastructure/api/users/__pycache__/app.cpython-312.pyc
Normal file
Binary file not shown.
BIN
src/infrastructure/api/users/__pycache__/app.cpython-314.pyc
Normal file
BIN
src/infrastructure/api/users/__pycache__/app.cpython-314.pyc
Normal file
Binary file not shown.
BIN
src/infrastructure/api/users/__pycache__/root.cpython-312.pyc
Normal file
BIN
src/infrastructure/api/users/__pycache__/root.cpython-312.pyc
Normal file
Binary file not shown.
BIN
src/infrastructure/api/users/__pycache__/root.cpython-314.pyc
Normal file
BIN
src/infrastructure/api/users/__pycache__/root.cpython-314.pyc
Normal file
Binary file not shown.
BIN
src/infrastructure/api/users/__pycache__/router.cpython-312.pyc
Normal file
BIN
src/infrastructure/api/users/__pycache__/router.cpython-312.pyc
Normal file
Binary file not shown.
BIN
src/infrastructure/api/users/__pycache__/router.cpython-314.pyc
Normal file
BIN
src/infrastructure/api/users/__pycache__/router.cpython-314.pyc
Normal file
Binary file not shown.
BIN
src/infrastructure/api/users/__pycache__/users.cpython-312.pyc
Normal file
BIN
src/infrastructure/api/users/__pycache__/users.cpython-312.pyc
Normal file
Binary file not shown.
BIN
src/infrastructure/api/users/__pycache__/users.cpython-314.pyc
Normal file
BIN
src/infrastructure/api/users/__pycache__/users.cpython-314.pyc
Normal file
Binary file not shown.
7
src/infrastructure/api/users/app.py
Normal file
7
src/infrastructure/api/users/app.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from fastapi import FastAPI
|
||||
from infrastructure.api.users.router import router
|
||||
|
||||
def create_app() -> FastAPI:
|
||||
app = FastAPI(title="Users service")
|
||||
app.include_router(router)
|
||||
return app
|
||||
10
src/infrastructure/api/users/root.py
Normal file
10
src/infrastructure/api/users/root.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.get("/")
|
||||
def root():
|
||||
return {
|
||||
"Status": "Running",
|
||||
"Docs": "/docs"
|
||||
}
|
||||
17
src/infrastructure/api/users/router.py
Normal file
17
src/infrastructure/api/users/router.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from fastapi import APIRouter
|
||||
from infrastructure.api.users.users import router as users_router
|
||||
from infrastructure.api.users.root import router as root_router
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
router.include_router(
|
||||
users_router,
|
||||
prefix="/users",
|
||||
tags=["users"]
|
||||
)
|
||||
|
||||
router.include_router(
|
||||
root_router,
|
||||
prefix='',
|
||||
tags=["root"]
|
||||
)
|
||||
44
src/infrastructure/api/users/users.py
Normal file
44
src/infrastructure/api/users/users.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from application.services.user_services import CreateUser, ViewUsers, ViewUserById
|
||||
from infrastructure.adapters.persistence.user_repository_sql import SqlUserRepository
|
||||
from application.exceptions import UserAlreadyExists
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.post("/")
|
||||
def create_user(name:str, email:str, phone:str):
|
||||
service = CreateUser(SqlUserRepository())
|
||||
|
||||
try:
|
||||
return service.execute(name,email,phone)
|
||||
except UserAlreadyExists as e:
|
||||
raise HTTPException (
|
||||
status_code=409,
|
||||
detail=str(e)
|
||||
)
|
||||
|
||||
|
||||
@router.get("/")
|
||||
def view_all_users():
|
||||
|
||||
service = ViewUsers(SqlUserRepository())
|
||||
|
||||
try:
|
||||
return service.execute()
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=e)
|
||||
|
||||
@router.get("/{id}")
|
||||
def view_user_by_id(user_id: int):
|
||||
service = ViewUserById(SqlUserRepository())
|
||||
|
||||
result = service.execute(user_id)
|
||||
|
||||
if result is None:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="User not found")
|
||||
|
||||
return result
|
||||
16
src/main.py
Normal file
16
src/main.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from infrastructure.api.users.app import create_app
|
||||
|
||||
app = create_app()
|
||||
|
||||
def run():
|
||||
import uvicorn
|
||||
uvicorn.run(
|
||||
"main:app",
|
||||
host="0.0.0.0",
|
||||
port=8000,
|
||||
reload=True,
|
||||
log_level="info",
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
run()
|
||||
BIN
src/users.db
Normal file
BIN
src/users.db
Normal file
Binary file not shown.
Reference in New Issue
Block a user