Skip to content

Commit c1a74ed

Browse files
authored
Adding APIs to UpsertGraphTemplate (#132)
* added models to create graph_template * fixed spell check * fixed comments by @coderabbitai * added graph create apis * removed extra f * added GrpahTemplate to main
1 parent bb58b8c commit c1a74ed

7 files changed

Lines changed: 150 additions & 7 deletions

File tree

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from app.singletons.logs_manager import LogsManager
2+
from app.models.graph_models import UpsertGraphTemplateRequest, UpsertGraphTemplateResponse
3+
from app.models.db.graph_template_model import GraphTemplate
4+
from app.models.graph_template_validation_status import GraphTemplateValidationStatus
5+
from beanie.operators import Set
6+
7+
logger = LogsManager().get_logger()
8+
9+
async def upsert_graph_template(namespace_name: str, graph_name: str, body: UpsertGraphTemplateRequest, x_exosphere_request_id: str) -> UpsertGraphTemplateResponse:
10+
try:
11+
graph_template = await GraphTemplate.find_one(
12+
GraphTemplate.name == graph_name,
13+
GraphTemplate.namespace == namespace_name
14+
)
15+
if graph_template:
16+
logger.info(
17+
"Graph template already exists in namespace", graph_template=graph_template,
18+
namespace_name=namespace_name,
19+
x_exosphere_request_id=x_exosphere_request_id)
20+
21+
await graph_template.update(
22+
Set({
23+
GraphTemplate.nodes: body.nodes, # type: ignore
24+
GraphTemplate.validation_status: GraphTemplateValidationStatus.PENDING, # type: ignore
25+
GraphTemplate.validation_errors: [] # type: ignore
26+
})
27+
)
28+
29+
else:
30+
logger.info(
31+
"Graph template does not exist in namespace",
32+
namespace_name=namespace_name,
33+
graph_name=graph_name,
34+
x_exosphere_request_id=x_exosphere_request_id)
35+
36+
graph_template = await GraphTemplate.insert(
37+
GraphTemplate(
38+
name=graph_name,
39+
namespace=namespace_name,
40+
nodes=body.nodes,
41+
validation_status=GraphTemplateValidationStatus.PENDING,
42+
validation_errors=[]
43+
)
44+
)
45+
46+
return UpsertGraphTemplateResponse(
47+
name=graph_template.name,
48+
namespace=graph_template.namespace,
49+
nodes=graph_template.nodes,
50+
validation_status=graph_template.validation_status,
51+
validation_errors=graph_template.validation_errors,
52+
created_at=graph_template.created_at,
53+
updated_at=graph_template.updated_at
54+
)
55+
56+
except Exception as e:
57+
logger.error("Error upserting graph template", error=e, x_exosphere_request_id=x_exosphere_request_id)
58+
raise e

state-manager/app/main.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
# injecting models
2121
from .models.db.state import State
2222
from .models.db.namespace import Namespace
23+
from .models.db.graph_template_model import GraphTemplate
2324

2425
# injecting routes
2526
from .routes import router
@@ -35,7 +36,7 @@ async def lifespan(app: FastAPI):
3536
# initializing beanie
3637
client = AsyncMongoClient(os.getenv("MONGO_URI"))
3738
db = client[os.getenv("MONGO_DATABASE_NAME", "exosphere-state-manager")]
38-
await init_beanie(db, document_models=[State, Namespace])
39+
await init_beanie(db, document_models=[State, Namespace, GraphTemplate])
3940
logger.info("beanie dbs initialized")
4041

4142
# initialize secret
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from .base import BaseDatabaseModel
2+
from pydantic import Field
3+
from typing import Optional, List
4+
from ..graph_template_validation_status import GraphTemplateValidationStatus
5+
from ..node_template_model import NodeTemplate
6+
from pymongo import IndexModel
7+
8+
9+
class GraphTemplate(BaseDatabaseModel):
10+
name: str = Field(..., description="Name of the graph")
11+
namespace: str = Field(..., description="Namespace of the graph")
12+
nodes: List[NodeTemplate] = Field(..., description="Nodes of the graph")
13+
validation_status: GraphTemplateValidationStatus = Field(..., description="Validation status of the graph")
14+
validation_errors: Optional[List[str]] = Field(None, description="Validation errors of the graph")
15+
16+
class Settings:
17+
indexes = [
18+
IndexModel(
19+
keys=[("name", 1), ("namespace", 1)],
20+
unique=True,
21+
name="unique_name_namespace"
22+
)
23+
]
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from .node_template_model import NodeTemplate
2+
from pydantic import BaseModel, Field
3+
from typing import List, Optional
4+
from datetime import datetime
5+
from .graph_template_validation_status import GraphTemplateValidationStatus
6+
7+
8+
class UpsertGraphTemplateRequest(BaseModel):
9+
name: str = Field(..., description="The name of the graph template")
10+
namespace: str = Field(..., description="The namespace where the graph template will be stored")
11+
nodes: List[NodeTemplate] = Field(..., description="List of node templates that define the graph structure")
12+
13+
14+
class UpsertGraphTemplateResponse(BaseModel):
15+
name: str = Field(..., description="The name of the graph template")
16+
namespace: str = Field(..., description="The namespace where the graph template is stored")
17+
nodes: List[NodeTemplate] = Field(..., description="List of node templates that define the graph structure")
18+
created_at: datetime = Field(..., description="Timestamp when the graph template was created")
19+
updated_at: datetime = Field(..., description="Timestamp when the graph template was last updated")
20+
validation_status: GraphTemplateValidationStatus = Field(..., description="Current validation status of the graph template")
21+
validation_errors: Optional[List[str]] = Field(None, description="List of validation errors if the graph template is invalid")
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from enum import Enum
2+
3+
4+
class GraphTemplateValidationStatus(str, Enum):
5+
VALID = "VALID"
6+
INVALID = "INVALID"
7+
PENDING = "PENDING"
8+
ONGOING = "ONGOING"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from pydantic import Field, BaseModel
2+
from typing import Any, Optional, List
3+
4+
5+
class NodeTemplate(BaseModel):
6+
node_name: str = Field(..., description="Name of the node")
7+
namespace: str = Field(..., description="Namespace of the node")
8+
identifier: str = Field(..., description="Identifier of the node")
9+
inputs: dict[str, Any] = Field(..., description="Inputs of the node")
10+
store: dict[str, Any] = Field(..., description="Upsert data to store object for the node")
11+
next_nodes: Optional[List[str]] = Field(None, description="Next nodes to execute")

state-manager/app/routes.py

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,18 @@
1818
from .models.errored_models import ErroredRequestModel, ErroredResponseModel
1919
from .controller.errored_state import errored_state
2020

21+
from .models.graph_models import UpsertGraphTemplateRequest, UpsertGraphTemplateResponse
22+
from .controller.upsert_graph_template import upsert_graph_template as upsert_graph_template_controller
23+
2124

2225

2326
logger = LogsManager().get_logger()
2427

25-
router = APIRouter(prefix="/v0/namespace/{namespace_name}/states", tags=["state"])
28+
router = APIRouter(prefix="/v0/namespace/{namespace_name}", tags=["state"])
2629

2730

2831
@router.post(
29-
"/enqueue",
32+
"/states/enqueue",
3033
response_model=EnqueueResponseModel,
3134
status_code=status.HTTP_200_OK,
3235
response_description="State enqueued on node queue successfully"
@@ -45,7 +48,7 @@ async def enqueue_state(namespace_name: str, body: EnqueueRequestModel, request:
4548

4649

4750
@router.post(
48-
"/create",
51+
"/states/create",
4952
response_model=CreateResponseModel,
5053
status_code=status.HTTP_200_OK,
5154
response_description="States created successfully"
@@ -64,7 +67,7 @@ async def create_state(namespace_name: str, body: CreateRequestModel, request: R
6467

6568

6669
@router.post(
67-
"/{state_id}/executed",
70+
"/states/{state_id}/executed",
6871
response_model=ExecutedResponseModel,
6972
status_code=status.HTTP_200_OK,
7073
response_description="State executed successfully"
@@ -83,7 +86,7 @@ async def executed_state_route(namespace_name: str, state_id: str, body: Execute
8386

8487

8588
@router.post(
86-
"/{state_id}/errored",
89+
"/states/{state_id}/errored",
8790
response_model=ErroredResponseModel,
8891
status_code=status.HTTP_200_OK,
8992
response_description="State errored successfully"
@@ -98,4 +101,22 @@ async def errored_state_route(namespace_name: str, state_id: str, body: ErroredR
98101
logger.error(f"API key is invalid for namespace {namespace_name}", x_exosphere_request_id=x_exosphere_request_id)
99102
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid API key")
100103

101-
return await errored_state(namespace_name, ObjectId(state_id), body, x_exosphere_request_id)
104+
return await errored_state(namespace_name, ObjectId(state_id), body, x_exosphere_request_id)
105+
106+
107+
@router.put(
108+
"/graph-templates/{graph_name}",
109+
response_model=UpsertGraphTemplateResponse,
110+
status_code=status.HTTP_200_OK,
111+
response_description="Graph template upserted successfully"
112+
)
113+
async def upsert_graph_template(namespace_name: str, graph_name: str, body: UpsertGraphTemplateRequest, request: Request, api_key: str = Depends(check_api_key)):
114+
x_exosphere_request_id = getattr(request.state, "x_exosphere_request_id", str(uuid4()))
115+
116+
if api_key:
117+
logger.info(f"API key is valid for namespace {namespace_name}", x_exosphere_request_id=x_exosphere_request_id)
118+
else:
119+
logger.error(f"API key is invalid for namespace {namespace_name}", x_exosphere_request_id=x_exosphere_request_id)
120+
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid API key")
121+
122+
return await upsert_graph_template_controller(namespace_name, graph_name, body, x_exosphere_request_id)

0 commit comments

Comments
 (0)