Skip to content

Commit

Permalink
FEAT: Enhance API Deployment Validation to Return 4xx Instead of 500 …
Browse files Browse the repository at this point in the history
…for Errors (#890)

* Added validation to execution_id and returning proper error status for execution requests

* Added validation for executions in serializers

* Merge branch 'main' into feat/improve-api-deployment-valdiation

* Merge branch 'main' into feat/improve-api-deployment-valdiation

* Added separate serialzers for GET api deployments

* Modified workflow_helper.py

* Modified workflow_helper.py

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Update workflow_helper.py

Signed-off-by: Praveen Kumar <[email protected]>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Update backend/api_v2/serializers.py

Co-authored-by: Chandrasekharan M <[email protected]>
Signed-off-by: Praveen Kumar <[email protected]>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Removed unnecesary try block in api_deployment_views.py

Signed-off-by: Praveen Kumar <[email protected]>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Update backend/workflow_manager/workflow_v2/workflow_helper.py

Co-authored-by: Chandrasekharan M <[email protected]>
Signed-off-by: Praveen Kumar <[email protected]>

* Moved checking for existence of execution to serializers

* Removed unused import in workflow_helper.py

* Update backend/api_v2/serializers.py

Co-authored-by: Chandrasekharan M <[email protected]>
Signed-off-by: Praveen Kumar <[email protected]>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Signed-off-by: Praveen Kumar <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Chandrasekharan M <[email protected]>
  • Loading branch information
3 people authored Dec 17, 2024
1 parent 8a01ca2 commit fdb5a0c
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 11 deletions.
19 changes: 11 additions & 8 deletions backend/api_v2/api_deployment_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
APIDeploymentListSerializer,
APIDeploymentSerializer,
DeploymentResponseSerializer,
ExecutionQuerySerializer,
ExecutionRequestSerializer,
)
from django.db.models import QuerySet
Expand Down Expand Up @@ -73,16 +74,18 @@ def post(
def get(
self, request: Request, org_name: str, api_name: str, api: APIDeployment
) -> Response:
execution_id = request.query_params.get("execution_id")
include_metadata = (
request.query_params.get(ApiExecution.INCLUDE_METADATA, "false").lower()
== "true"
)
if not execution_id:
raise InvalidAPIRequest("execution_id shouldn't be empty")
serializer = ExecutionQuerySerializer(data=request.query_params)
serializer.is_valid(raise_exception=True)

execution_id = serializer.validated_data.get(ApiExecution.EXECUTION_ID)
include_metadata = serializer.validated_data.get(ApiExecution.INCLUDE_METADATA)

# Fetch execution status
response: ExecutionResponse = DeploymentHelper.get_execution_status(
execution_id=execution_id
execution_id
)

# Determine response status
response_status = status.HTTP_422_UNPROCESSABLE_ENTITY
if response.execution_status == CeleryTaskState.COMPLETED.value:
response_status = status.HTTP_200_OK
Expand Down
1 change: 1 addition & 0 deletions backend/api_v2/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ class ApiExecution:
TIMEOUT_FORM_DATA: str = "timeout"
INCLUDE_METADATA: str = "include_metadata"
USE_FILE_HISTORY: str = "use_file_history" # Undocumented parameter
EXECUTION_ID: str = "execution_id"
29 changes: 29 additions & 0 deletions backend/api_v2/serializers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import uuid
from collections import OrderedDict
from typing import Any, Union

Expand All @@ -15,6 +16,8 @@
ValidationError,
)
from utils.serializer.integrity_error_mixin import IntegrityErrorMixin
from workflow_manager.workflow_v2.exceptions import ExecutionDoesNotExistError
from workflow_manager.workflow_v2.models.execution import WorkflowExecution

from backend.serializers import AuditSerializer

Expand Down Expand Up @@ -115,6 +118,32 @@ class ExecutionRequestSerializer(Serializer):
use_file_history = BooleanField(default=False)


class ExecutionQuerySerializer(Serializer):
execution_id = CharField(required=True)
include_metadata = BooleanField(default=False)

def validate_execution_id(self, value):
"""Trim spaces, validate UUID format, and check if execution_id exists."""
value = value.strip()

# Validate UUID format
try:
uuid_obj = uuid.UUID(value)
except ValueError:
raise ValidationError(
f"Invalid execution_id '{value}'. Must be a valid UUID."
)

# Check if UUID exists in the database
exists = WorkflowExecution.objects.filter(id=uuid_obj).exists()
if not exists:
raise ExecutionDoesNotExistError(
f"Execution with ID '{value}' does not exist."
)

return str(uuid_obj)


class APIDeploymentListSerializer(ModelSerializer):
workflow_name = CharField(source="workflow.workflow_name", read_only=True)

Expand Down
5 changes: 5 additions & 0 deletions backend/workflow_manager/workflow_v2/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ class WorkflowDoesNotExistError(APIException):
default_detail = "Workflow does not exist"


class ExecutionDoesNotExistError(APIException):
status_code = 404
default_detail = "Execution does not exist."


class TaskDoesNotExistError(APIException):
status_code = 404
default_detail = "Task does not exist"
Expand Down
7 changes: 4 additions & 3 deletions backend/workflow_manager/workflow_v2/workflow_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -414,17 +414,18 @@ def get_status_of_async_task(
Raises:
TaskDoesNotExistError: Not found exception
ExecutionDoesNotExistError: If execution is not found
Returns:
ExecutionResponse: _description_
"""
execution = WorkflowExecution.objects.get(id=execution_id)

if not execution.task_id:
raise TaskDoesNotExistError()
raise TaskDoesNotExistError(
f"No task ID found for execution: {execution_id}"
)

result = AsyncResult(str(execution.task_id))

task = AsyncResultData(async_result=result)

# Prepare the initial response with the task's current status and result.
Expand Down

0 comments on commit fdb5a0c

Please sign in to comment.