wag-managment-api-service-l.../Scratches/endpoint.py

173 lines
6.0 KiB
Python

from dataclasses import dataclass, field
from typing import List, Optional, Dict, Any, Callable
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from typing import Union
# First, let's create our category models
class CategoryBase(BaseModel):
id: str
name: str
description: Optional[str] = None
class CategoryCreate(CategoryBase):
parent_id: Optional[str] = None
class CategoryResponse(CategoryBase):
children: List["CategoryResponse"] = []
parent_id: Optional[str] = None
# Category data structure for handling the hierarchy
@dataclass
class CategoryNode:
id: str
name: str
description: Optional[str]
parent_id: Optional[str] = None
children: List["CategoryNode"] = field(default_factory=list)
# Category Service for managing the hierarchy
class CategoryService:
def __init__(self):
self.categories: Dict[str, CategoryNode] = {}
def add_category(self, category: CategoryCreate) -> CategoryNode:
node = CategoryNode(
id=category.id,
name=category.name,
description=category.description,
parent_id=category.parent_id,
)
self.categories[category.id] = node
if category.parent_id and category.parent_id in self.categories:
parent = self.categories[category.parent_id]
parent.children.append(node)
return node
def get_category_tree(self, category_id: str) -> Optional[CategoryNode]:
return self.categories.get(category_id)
def get_category_path(self, category_id: str) -> List[CategoryNode]:
path = []
current = self.categories.get(category_id)
while current:
path.append(current)
current = (
self.categories.get(current.parent_id) if current.parent_id else None
)
return list(reversed(path))
# Factory for creating category endpoints
class CategoryEndpointFactory:
def __init__(self, category_service: CategoryService):
self.category_service = category_service
def create_route_config(self, base_prefix: str) -> RouteFactoryConfig:
endpoints = [
# Create category endpoint
EndpointFactoryConfig(
url_prefix=base_prefix,
url_endpoint="/categories",
url_of_endpoint=f"{base_prefix}/categories",
endpoint="/categories",
method="POST",
summary="Create new category",
description="Create a new category with optional parent",
endpoint_function=self.create_category,
request_model=CategoryCreate,
response_model=CategoryResponse,
is_auth_required=True,
),
# Get category tree endpoint
EndpointFactoryConfig(
url_prefix=base_prefix,
url_endpoint="/categories/{category_id}",
url_of_endpoint=f"{base_prefix}/categories/{{category_id}}",
endpoint="/categories/{category_id}",
method="GET",
summary="Get category tree",
description="Get category and its children",
endpoint_function=self.get_category_tree,
response_model=CategoryResponse,
is_auth_required=True,
),
# Get category path endpoint
EndpointFactoryConfig(
url_prefix=base_prefix,
url_endpoint="/categories/{category_id}/path",
url_of_endpoint=f"{base_prefix}/categories/{{category_id}}/path",
endpoint="/categories/{category_id}/path",
method="GET",
summary="Get category path",
description="Get full path from root to this category",
endpoint_function=self.get_category_path,
response_model=List[CategoryResponse],
is_auth_required=True,
),
]
return RouteFactoryConfig(
name="categories",
tags=["Categories"],
prefix=base_prefix,
endpoints=endpoints,
)
async def create_category(self, category: CategoryCreate) -> CategoryResponse:
node = self.category_service.add_category(category)
return self._convert_to_response(node)
async def get_category_tree(self, category_id: str) -> CategoryResponse:
node = self.category_service.get_category_tree(category_id)
if not node:
raise HTTPException(status_code=404, detail="Category not found")
return self._convert_to_response(node)
async def get_category_path(self, category_id: str) -> List[CategoryResponse]:
path = self.category_service.get_category_path(category_id)
if not path:
raise HTTPException(status_code=404, detail="Category not found")
return [self._convert_to_response(node) for node in path]
def _convert_to_response(self, node: CategoryNode) -> CategoryResponse:
return CategoryResponse(
id=node.id,
name=node.name,
description=node.description,
parent_id=node.parent_id,
children=[self._convert_to_response(child) for child in node.children],
)
# Usage example
def create_category_router(base_prefix: str = "/api/v1") -> APIRouter:
category_service = CategoryService()
factory = CategoryEndpointFactory(category_service)
route_config = factory.create_route_config(base_prefix)
router = APIRouter(prefix=route_config.prefix, tags=route_config.tags)
for endpoint in route_config.endpoints:
router.add_api_route(
path=endpoint.endpoint,
endpoint=endpoint.endpoint_function,
methods=[endpoint.method],
response_model=endpoint.response_model,
summary=endpoint.summary,
description=endpoint.description,
**endpoint.extra_options,
)
return router