routes.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. from core_domain import ServiceHealth
  2. from core_shared.secrets import SecretCipher
  3. from fastapi import APIRouter, Depends, HTTPException, Query, Request
  4. from sqlalchemy import text
  5. from sqlalchemy.orm import Session
  6. from app.application.services import ToolApplicationService
  7. from app.bootstrap.settings import ToolServiceSettings
  8. from app.db.session import get_db
  9. from app.domain.repositories import (
  10. ToolBindingRepository,
  11. ToolCredentialRepository,
  12. ToolDefinitionRepository,
  13. ToolVersionRepository,
  14. )
  15. from app.schemas.tool import (
  16. ToolBindingCreateRequest,
  17. ToolBindingDetailResponse,
  18. ToolBindingResponse,
  19. ToolCreateRequest,
  20. ToolCredentialCreateRequest,
  21. ToolCredentialResponse,
  22. ToolCredentialRevealResponse,
  23. ToolResponse,
  24. ToolVersionCreateRequest,
  25. ToolVersionResponse,
  26. )
  27. router = APIRouter()
  28. def get_tool_application_service(
  29. request: Request,
  30. db: Session = Depends(get_db)) -> ToolApplicationService:
  31. settings: ToolServiceSettings = request.app.state.settings
  32. return ToolApplicationService(
  33. tool_definition_repository=ToolDefinitionRepository(db),
  34. tool_version_repository=ToolVersionRepository(db),
  35. tool_binding_repository=ToolBindingRepository(db),
  36. tool_credential_repository=ToolCredentialRepository(db),
  37. secret_cipher=SecretCipher(key=settings.credential_encryption_key))
  38. @router.get("/health", response_model=ServiceHealth)
  39. def health_check(db: Session = Depends(get_db)) -> ServiceHealth:
  40. db.execute(text("SELECT 1"))
  41. return ServiceHealth(service="tool-service", status="ok", database="ok")
  42. @router.post("", response_model=ToolResponse)
  43. def create_tool_definition(
  44. payload: ToolCreateRequest,
  45. service: ToolApplicationService = Depends(get_tool_application_service)) -> ToolResponse:
  46. entity = service.create_tool_definition(payload)
  47. return ToolResponse.from_entity(entity)
  48. @router.get("", response_model=list[ToolResponse])
  49. def list_tool_definitions(
  50. service: ToolApplicationService = Depends(get_tool_application_service)) -> list[ToolResponse]:
  51. return [ToolResponse.from_entity(item) for item in service.list_tool_definitions()]
  52. @router.post("/versions", response_model=ToolVersionResponse)
  53. def create_tool_version(
  54. payload: ToolVersionCreateRequest,
  55. service: ToolApplicationService = Depends(get_tool_application_service)) -> ToolVersionResponse:
  56. entity = service.create_tool_version(payload)
  57. return ToolVersionResponse.from_entity(entity)
  58. @router.get("/versions", response_model=list[ToolVersionResponse])
  59. def list_tool_versions(
  60. tool_id: str | None = Query(default=None),
  61. service: ToolApplicationService = Depends(get_tool_application_service)) -> list[ToolVersionResponse]:
  62. return [
  63. ToolVersionResponse.from_entity(item)
  64. for item in service.list_tool_versions(tool_id=tool_id)
  65. ]
  66. @router.post("/bindings", response_model=ToolBindingResponse)
  67. def create_tool_binding(
  68. payload: ToolBindingCreateRequest,
  69. service: ToolApplicationService = Depends(get_tool_application_service)) -> ToolBindingResponse:
  70. try:
  71. entity = service.create_tool_binding(payload)
  72. except ValueError as exc:
  73. raise HTTPException(status_code=422, detail=str(exc)) from exc
  74. return ToolBindingResponse.from_entity(entity)
  75. @router.get("/bindings", response_model=list[ToolBindingResponse])
  76. def list_tool_bindings(
  77. app_id: str | None = Query(default=None),
  78. service: ToolApplicationService = Depends(get_tool_application_service)) -> list[ToolBindingResponse]:
  79. return [
  80. ToolBindingResponse.from_entity(item)
  81. for item in service.list_tool_bindings(app_id=app_id)
  82. ]
  83. @router.get("/bindings/{binding_id}", response_model=ToolBindingDetailResponse)
  84. def get_tool_binding_detail(
  85. binding_id: str,
  86. service: ToolApplicationService = Depends(get_tool_application_service)) -> ToolBindingDetailResponse:
  87. result = service.get_tool_binding_detail(binding_id=binding_id)
  88. if result is None:
  89. raise HTTPException(status_code=404, detail=f"tool_binding not found: {binding_id}")
  90. binding, tool_version, tool_definition = result
  91. return ToolBindingDetailResponse(
  92. binding=ToolBindingResponse.from_entity(binding),
  93. tool_version=ToolVersionResponse.from_entity(tool_version),
  94. tool_definition=ToolResponse.from_entity(tool_definition))
  95. @router.post("/credentials", response_model=ToolCredentialResponse)
  96. def create_tool_credential(
  97. payload: ToolCredentialCreateRequest,
  98. service: ToolApplicationService = Depends(get_tool_application_service)) -> ToolCredentialResponse:
  99. entity = service.create_tool_credential(payload)
  100. return ToolCredentialResponse.from_entity(entity)
  101. @router.get("/credentials", response_model=list[ToolCredentialResponse])
  102. def list_tool_credentials(
  103. service: ToolApplicationService = Depends(get_tool_application_service)) -> list[ToolCredentialResponse]:
  104. return [
  105. ToolCredentialResponse.from_entity(item)
  106. for item in service.list_tool_credentials()
  107. ]
  108. @router.post("/credentials/{credential_id}/reveal", response_model=ToolCredentialRevealResponse)
  109. def reveal_tool_credential(
  110. credential_id: str,
  111. service: ToolApplicationService = Depends(get_tool_application_service)) -> ToolCredentialRevealResponse:
  112. result = service.reveal_tool_credential(
  113. credential_id=credential_id)
  114. if result is None:
  115. raise HTTPException(status_code=404, detail=f"tool credential not found: {credential_id}")
  116. credential, secret_json = result
  117. return ToolCredentialRevealResponse(
  118. credential=ToolCredentialResponse.from_entity(credential),
  119. secret_json=secret_json)