first commit

This commit is contained in:
2026-02-13 17:00:52 -06:00
commit 07a6d7069f
49 changed files with 763 additions and 0 deletions

Binary file not shown.

View File

@@ -0,0 +1,2 @@
class MicroserviceAlreadyExists(Exception):
pass

View File

@@ -0,0 +1,19 @@
from abc import ABC, abstractmethod
from domain.MicroservicioA import MicroservicioA
class MicroservicioARepository(ABC):
@abstractmethod
def save(self, msa: MicroservicioA):
...
@abstractmethod
def viewAll(self) -> list[MicroservicioA]:
...
@abstractmethod
def viewById(self, msa_id: int):
...
@abstractmethod
def remove(self, msa_id: int):
...
@abstractmethod
def editById(self, msa_id: int, msa: MicroservicioA):
...

View File

@@ -0,0 +1,19 @@
from abc import ABC, abstractmethod
from domain.MicroservicioB import MicroservicioB
class MicroservicioBRepository(ABC):
@abstractmethod
def save(self, msb: MicroservicioB):
...
@abstractmethod
def viewAll(self) -> list[MicroservicioB]:
...
@abstractmethod
def viewById(self, msb_id: int):
...
@abstractmethod
def remove(self, msb_id: int):
...
@abstractmethod
def editById(self, msb_id:int, msb: MicroservicioB):
...

View File

@@ -0,0 +1,4 @@
from infrastructure.adapters.persistence.db import engine
from infrastructure.adapters.persistence.models import Base
Base.metadata.create_all(bind=engine)

View File

@@ -0,0 +1,57 @@
from application.ports.microservicio_a_repository import MicroservicioARepository
from domain.MicroservicioA import MicroservicioA
class Save:
def __init__(self, repo: MicroservicioARepository):
if not isinstance(repo, MicroservicioARepository):
raise TypeError("MicroservicioARepository must be a class instance")
self.repo = repo
def execute(self, perfiles: str, idioma: str, calidad: str):
msa = MicroservicioA(msa_id=0,perfiles=perfiles, idioma=idioma,calidad=calidad)
self.repo.save(msa)
return msa
class ViewAllMsa:
def __init__(self, repo: MicroservicioARepository):
if not isinstance(repo, MicroservicioARepository):
raise TypeError("MicroservicioARepository must be a class instance")
self.repo = repo
def execute(self):
msa_s = self.repo.viewAll()
return msa_s
class ViewById:
def __init__(self, repo: MicroservicioARepository):
if not isinstance(repo, MicroservicioARepository):
raise TypeError("MicroservicioARepository must be a class instance")
self.repo = repo
def execute(self, msa_id: int) -> MicroservicioA | None:
msa = self.repo.viewById(msa_id)
return msa
class Remove:
def __init__(self, repo: MicroservicioARepository):
if not isinstance(repo, MicroservicioARepository):
raise TypeError("MicroservicioARepository must be a class instance")
self.repo = repo
def execute(self, msa_id:int):
msa = self.repo.remove(msa_id)
return msa
class EditById:
def __init__(self, repo: MicroservicioARepository):
if not isinstance(repo, MicroservicioARepository):
raise TypeError("MicroservicioARepository must be a class instance")
self.repo = repo
def execute(self, msa_id: int, msa: MicroservicioA):
return self.repo.editById(msa_id=msa_id, msa=msa)

View File

@@ -0,0 +1,56 @@
from application.ports.microservicio_b_repository import MicroservicioBRepository
from domain.MicroservicioB import MicroservicioB
class Save:
def __init__(self, repo: MicroservicioBRepository):
if not isinstance(repo, MicroservicioBRepository):
raise TypeError("MicroservicioBRepository must be a class instance")
self.repo = repo
def execute(self, metodoPagoPredeterminado: str, historialFacturas: str, fechaProximoPago: str):
msb = MicroservicioB(msb_id=0, metodoPagoPredeterminado=metodoPagoPredeterminado, historialFacturas=historialFacturas, fechaProximoPago=fechaProximoPago)
self.repo.save(msb)
return msb
class ViewAllMsb:
def __init__(self, repo: MicroservicioBRepository):
if not isinstance(repo, MicroservicioBRepository):
raise TypeError("MicroservicioBRepository must be a class instance")
self.repo = repo
def execute(self):
msb_s = self.repo.viewAll()
return msb_s
class ViewById:
def __init__(self, repo: MicroservicioBRepository):
if not isinstance(repo, MicroservicioBRepository):
raise TypeError("MicroservicioBRepository must be a class instance")
self.repo = repo
def execute(self, msb_id: int) -> MicroservicioB | None:
msb = self.repo.viewById(msb_id)
return msb
class Remove:
def __init__(self, repo: MicroservicioBRepository):
if not isinstance(repo, MicroservicioBRepository):
raise TypeError("MicroservicioBRepository must be a class instance")
self.repo = repo
def execute(self, msb_id:int):
msb = self.repo.remove(msb_id)
return msb
class EditById:
def __init__(self, repo: MicroservicioBRepository):
if not isinstance(repo, MicroservicioBRepository):
raise TypeError("MicroservicioBRepository must be a class instance")
self.repo = repo
def execute(self, msb_id: int, msb: MicroservicioB):
return self.repo.editById(msb_id=msb_id, msb=msb)

Binary file not shown.

23
src/core/config.py Normal file
View File

@@ -0,0 +1,23 @@
from pydantic_settings import BaseSettings
from pydantic import Field
class Settings(BaseSettings):
reload: bool = True
host: str = "0.0.0.0"
log_level:str = "info"
database_url: str = Field(default="sqlite:///./database.db", description="database")
# API A
api_a_title: str = "Microservicio A API"
api_a_version:str= "1.0.0"
api_a_description:str = "Catálogo y reproducción de contenido"
api_a_port: int = 8001
# API B
api_b_title: str = "Microservicio B API"
api_b_version:str= "1.0.0"
api_b_description:str = "Encargado de recomendaciones y \"Mi Lista\""
api_b_port: int = 8002
ConfSettings = Settings()

BIN
src/database.db Normal file

Binary file not shown.

View File

@@ -0,0 +1,8 @@
from dataclasses import dataclass
@dataclass
class MicroservicioA:
msa_id: int
perfiles: str
idioma: str
calidad: str

View File

@@ -0,0 +1,8 @@
from dataclasses import dataclass
@dataclass
class MicroservicioB:
msb_id: int
metodoPagoPredeterminado: str
historialFacturas: str
fechaProximoPago: str

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,16 @@
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, declarative_base
from core.config import ConfSettings
engine = create_engine(
ConfSettings.database_url,
connect_args={"check_same_thread": False} if "sqlite" in ConfSettings.database_url else {}
)
SessionLocal = sessionmaker(
bind=engine,
autocommit=False,
autoflush=False
)
Base = declarative_base()

View File

@@ -0,0 +1,99 @@
from sqlalchemy.orm import Session
from sqlalchemy.exc import IntegrityError
from domain.MicroservicioA import MicroservicioA
from application.ports.microservicio_a_repository import MicroservicioARepository
from infrastructure.adapters.persistence.db import SessionLocal
from infrastructure.adapters.persistence.models import MsaModel
from application.exceptions import MicroserviceAlreadyExists
class SqlMicroservicioARepository(MicroservicioARepository):
def __init__(self):
self.db: Session = SessionLocal()
def save(self, msa: MicroservicioA):
model = MsaModel(
perfiles=msa.perfiles,
idioma=msa.idioma,
calidad=msa.calidad
)
self.db.add(model)
try:
self.db.commit()
except IntegrityError:
self.db.rollback()
raise MicroserviceAlreadyExists("There's already one registry with that data.")
self.db.refresh(model)
return MicroservicioA(
msa_id = model.msa_id,
perfiles=model.perfiles,
idioma=model.idioma,
calidad=model.calidad
)
def viewAll(self) -> list[MicroservicioA]:
models = self.db.query(MsaModel).all()
return [
MicroservicioA(
msa_id=model.msa_id,
perfiles=model.perfiles,
idioma=model.idioma,
calidad=model.calidad
) for model in models
]
def viewById(self, msa_id: int) -> MicroservicioA | None:
model = self.db.query(MsaModel).filter(MsaModel.msa_id == msa_id).first()
if not model:
return None
return MicroservicioA(
msa_id=model.msa_id,
perfiles=model.perfiles,
idioma=model.idioma,
calidad=model.calidad
)
def remove(self, msa_id: int):
model = self.db.query(MsaModel).filter(MsaModel.msa_id == msa_id).first()
if not model:
return False
try:
self.db.delete(model)
self.db.commit()
return True
except IntegrityError:
self.db.rollback()
raise MicroserviceAlreadyExists("There's already one registry with that data.")
def editById(self, msa_id: int, msa: MicroservicioA) -> MicroservicioA | None:
model = self.db.query(MsaModel).filter(MsaModel.msa_id == msa_id).first()
if not model:
return None
try:
model.perfiles = msa.perfiles
model.idioma = msa.idioma
model.calidad = msa.calidad
self.db.commit()
self.db.refresh(model)
return MicroservicioA(
msa_id=model.msa_id,
perfiles=model.perfiles,
idioma=model.idioma,
calidad=model.calidad
)
except IntegrityError:
self.db.rollback()
raise MicroserviceAlreadyExists("There's already one registry with that data.")

View File

@@ -0,0 +1,99 @@
from sqlalchemy.orm import Session
from sqlalchemy.exc import IntegrityError
from domain.MicroservicioB import MicroservicioB
from application.ports.microservicio_b_repository import MicroservicioBRepository
from infrastructure.adapters.persistence.db import SessionLocal
from infrastructure.adapters.persistence.models import MsbModel
from application.exceptions import MicroserviceAlreadyExists
class SqlMicroservicioBRepository(MicroservicioBRepository):
def __init__(self):
self.db: Session = SessionLocal()
def save(self, msb: MicroservicioB):
model = MsbModel(
metodoPagoPredeterminado=msb.metodoPagoPredeterminado,
historialFacturas=msb.historialFacturas,
fechaProximoPago=msb.fechaProximoPago
)
self.db.add(model)
try:
self.db.commit()
except IntegrityError:
self.db.rollback()
raise MicroserviceAlreadyExists("There's already one registry with that data.")
self.db.refresh(model)
return MicroservicioB(
msb_id = model.msb_id,
metodoPagoPredeterminado=model.metodoPagoPredeterminado,
historialFacturas=model.historialFacturas,
fechaProximoPago=model.fechaProximoPago
)
def viewAll(self) -> list[MicroservicioB]:
models = self.db.query(MsbModel).all()
return [
MicroservicioB(
msb_id=model.msb_id,
metodoPagoPredeterminado=model.metodoPagoPredeterminado,
historialFacturas=model.historialFacturas,
fechaProximoPago=model.fechaProximoPago
) for model in models
]
def viewById(self, msb_id: int) -> MicroservicioB | None:
model = self.db.query(MsbModel).filter(MsbModel.msb_id == msb_id).first()
if not model:
return None
return MicroservicioB(
msb_id=model.msb_id,
metodoPagoPredeterminado=model.metodoPagoPredeterminado,
historialFacturas=model.historialFacturas,
fechaProximoPago=model.fechaProximoPago
)
def remove(self, msb_id: int):
model = self.db.query(MsbModel).filter(MsbModel.msb_id == msb_id).first()
if not model:
return False
try:
self.db.delete(model)
self.db.commit()
return True
except IntegrityError:
self.db.rollback()
raise MicroserviceAlreadyExists("There's already one registry with that data.")
def editById(self, msb_id: int, msb: MicroservicioB) -> MicroservicioB | None:
model = self.db.query(MsbModel).filter(MsbModel.msb_id == msb_id).first()
if not model:
return None
try:
model.metodoPagoPredeterminado = msb.metodoPagoPredeterminado
model.historialFacturas = msb.historialFacturas
model.fechaProximoPago = msb.fechaProximoPago
self.db.commit()
self.db.refresh(model)
return MicroservicioB(
msb_id=model.msb_id,
metodoPagoPredeterminado=model.metodoPagoPredeterminado,
historialFacturas=model.historialFacturas,
fechaProximoPago=model.fechaProximoPago
)
except IntegrityError:
self.db.rollback()
raise MicroserviceAlreadyExists("There's already one registry with that data.")

View File

@@ -0,0 +1,19 @@
from sqlalchemy import Column, Integer, String, Float, DateTime
from infrastructure.adapters.persistence.db import Base
class MsaModel(Base):
__tablename__ = "microservicioa"
msa_id = Column(Integer, primary_key=True, index=True)
perfiles = Column(String, unique=False, index=True)
idioma = Column(String, unique=True, index=True)
calidad = Column(String, unique=True, index=True)
class MsbModel(Base):
__tablename__ = "microserviciob"
msb_id = Column(Integer, primary_key=True, index=True)
metodoPagoPredeterminado = Column(String, unique=False, index=True)
historialFacturas = Column(String, unique=False, index=True)
fechaProximoPago = Column(String, unique=False, index=True)

View File

@@ -0,0 +1,10 @@
from fastapi import FastAPI
from core.config import ConfSettings
from infrastructure.api.microservicio_a.router import router
def create_app() -> FastAPI:
app = FastAPI(title=ConfSettings.api_a_title,
version=ConfSettings.api_a_version,
description=ConfSettings.api_a_description)
app.include_router(router)
return app

View File

@@ -0,0 +1,79 @@
from fastapi import APIRouter, HTTPException
from application.services.microservicio_a_service import Save, ViewAllMsa, ViewById, Remove, EditById
from infrastructure.adapters.persistence.microservicio_a_repository_sql import SqlMicroservicioARepository
from domain.MicroservicioA import MicroservicioA
router = APIRouter()
@router.post("/")
def create_msa(perfiles: str, idioma: str, calidad: str):
service = Save(SqlMicroservicioARepository())
try:
return service.execute(perfiles, idioma, calidad)
except Exception as e:
raise HTTPException(
status_code=400,
detail=str(e)
)
@router.get("/")
def view_all_msa():
service = ViewAllMsa(SqlMicroservicioARepository())
try:
return service.execute()
except Exception as e:
raise HTTPException(
status_code=500,
detail=str(e)
)
@router.get("/{msa_id}")
def view_msa_by_id(msa_id: int):
service = ViewById(SqlMicroservicioARepository())
result = service.execute(msa_id)
if result is None:
raise HTTPException(
status_code=404,
detail="Microservice not found"
)
return result
@router.delete("/{msa_id}")
def delete_msa_by_id(msa_id: int):
service = Remove(SqlMicroservicioARepository())
result = service.execute(msa_id)
if result is None:
raise HTTPException(
status_code=404,
detail="Microservice not found"
)
return result
@router.put("/{msa_id}")
def edit_msa_by_id(msa_id: int, perfiles: str, idioma: str, calidad: str):
service = EditById(SqlMicroservicioARepository())
try:
msa = MicroservicioA(msa_id=msa_id, perfiles=perfiles, idioma=idioma, calidad=calidad)
result = service.execute(msa_id=msa_id, msa=msa)
except Exception as e:
raise HTTPException(
status_code=500,
detail=str(e)
)
if result is None:
raise HTTPException(
status_code=404,
detail="Microservice not found"
)
return result

View File

@@ -0,0 +1,16 @@
from fastapi import APIRouter
import platform
router = APIRouter()
@router.get("/")
def root():
uname = platform.uname()
return {
"machine": {
"OS": f"{uname.system} {uname.release}",
"Arch": uname.machine
},
"Status": "Running",
"Docs": "/docs"
}

View File

@@ -0,0 +1,17 @@
from fastapi import APIRouter
from infrastructure.api.microservicio_a.microservices import router as orders_router
from infrastructure.api.microservicio_a.root import router as root_router
router = APIRouter()
router.include_router(
orders_router,
prefix="/microservicio_a",
tags=["microservicio a"]
)
router.include_router(
root_router,
prefix='',
tags=["root"]
)

View File

@@ -0,0 +1,10 @@
from fastapi import FastAPI
from core.config import ConfSettings
from infrastructure.api.microservicio_b.router import router
def create_app() -> FastAPI:
app = FastAPI(title=ConfSettings.api_b_title,
version=ConfSettings.api_b_version,
description=ConfSettings.api_b_description)
app.include_router(router)
return app

View File

@@ -0,0 +1,79 @@
from fastapi import APIRouter, HTTPException
from application.services.microservicio_b_service import Save, ViewAllMsb, ViewById, Remove, EditById
from infrastructure.adapters.persistence.microservicio_b_repository_sql import SqlMicroservicioBRepository
from domain.MicroservicioB import MicroservicioB
router = APIRouter()
@router.post("/")
def create_msb(metodoPagoPredeterminado: str, historialFacturas: str, fechaProximoPago: str):
service = Save(SqlMicroservicioBRepository())
try:
return service.execute(metodoPagoPredeterminado, historialFacturas, fechaProximoPago)
except Exception as e:
raise HTTPException(
status_code=400,
detail=str(e)
)
@router.get("/")
def view_all_msb():
service = ViewAllMsb(SqlMicroservicioBRepository())
try:
return service.execute()
except Exception as e:
raise HTTPException(
status_code=500,
detail=str(e)
)
@router.get("/{msb_id}")
def view_msb_by_id(msb_id: int):
service = ViewById(SqlMicroservicioBRepository())
result = service.execute(msb_id)
if result is None:
raise HTTPException(
status_code=404,
detail="Microservice not found"
)
return result
@router.delete("/{msb_id}")
def delete_msb_by_id(msb_id: int):
service = Remove(SqlMicroservicioBRepository())
result = service.execute(msb_id)
if result is None:
raise HTTPException(
status_code=404,
detail="Microservice not found"
)
return result
@router.put("/{msb_id}")
def edit_msb_by_id(msb_id: int, metodoPagoPredeterminado: str, historialFacturas: str, fechaProximoPago: str):
service = EditById(SqlMicroservicioBRepository())
try:
msb = MicroservicioB(msb_id=msb_id, metodoPagoPredeterminado=metodoPagoPredeterminado, historialFacturas=historialFacturas, fechaProximoPago=fechaProximoPago)
result = service.execute(msb_id=msb_id, msb=msb)
except Exception as e:
raise HTTPException(
status_code=500,
detail=str(e)
)
if result is None:
raise HTTPException(
status_code=404,
detail="Microservice not found"
)
return result

View File

@@ -0,0 +1,16 @@
from fastapi import APIRouter
import platform
router = APIRouter()
@router.get("/")
def root():
uname = platform.uname()
return {
"machine": {
"OS": f"{uname.system} {uname.release}",
"Arch": uname.machine
},
"Status": "Running",
"Docs": "/docs"
}

View File

@@ -0,0 +1,17 @@
from fastapi import APIRouter
from infrastructure.api.microservicio_b.microservices import router as microservices_router
from infrastructure.api.microservicio_b.root import router as root_router
router = APIRouter()
router.include_router(
microservices_router,
prefix="/microservicio_b",
tags=["microservicio b"]
)
router.include_router(
root_router,
prefix='',
tags=["root"]
)

52
src/main.py Normal file
View File

@@ -0,0 +1,52 @@
from infrastructure.api.microservicio_a.app import create_app as create_msa_app
from infrastructure.api.microservicio_b.app import create_app as create_msb_app
from core.config import ConfSettings
import threading
import uvicorn
def run_msa_api():
"""Ejecuta la API de usuarios en puerto 8000"""
app_msa_app = create_msa_app()
uvicorn.run(
app_msa_app,
host=ConfSettings.host,
port=ConfSettings.api_a_port,
reload=False,
log_level=ConfSettings.log_level,
)
def run_msb_api():
"""Ejecuta la API del microservicio B"""
app_msb_app = create_msb_app()
uvicorn.run(
app_msb_app,
host=ConfSettings.host,
port=ConfSettings.api_b_port,
reload=False,
log_level=ConfSettings.log_level,
)
def run():
"""Inicia ambas APIs en threads separados"""
print("Iniciando microservicios...")
msa_thread = threading.Thread(target=run_msa_api, daemon=True, name="Microservice-A-API")
msb_thread = threading.Thread(target=run_msb_api, daemon=True, name="Microservice-B-API")
msa_thread.start()
msb_thread.start()
print("API del microservicio A ejecutándose en http://0.0.0.0:" + str(ConfSettings.api_a_port))
print("API del microservicio B ejecutándose en http://0.0.0.0:" + str(ConfSettings.api_b_port))
print("\nDocumentación disponible en:")
print(" - Microservicio A: http://localhost:" + str(ConfSettings.api_a_port) + "/docs")
print(" - Microservicio B: http://localhost:" + str(ConfSettings.api_b_port) + "/docs")
try:
msa_thread.join()
msb_thread.join()
except KeyboardInterrupt:
print("\n\nAteniendo señal de salida...")
if __name__ == "__main__":
run()