buster/api/prds/active/api_post_chat_rest_endpoint.md

8.5 KiB

title author date status parent_prd
REST Post Chat Endpoint Implementation Dallin 2025-03-21 Draft optional_prompt_asset_chat.md

REST Post Chat Endpoint Implementation

Parent Project

This is a sub-PRD of the Optional Prompt Asset Chat System project. Please refer to the parent PRD for the overall project context, goals, and implementation plan.

Problem Statement

The current REST endpoint for creating chats (post_chat_route) expects a prompt as a required field and handles specific asset types through separate parameters (metric_id and dashboard_id). To support the parent project's goals, this endpoint needs to be updated to accept an optional prompt when an asset is provided and to use a more generic asset reference model.

This component will update the REST endpoint to:

  1. Accept requests with optional prompts when an asset is provided
  2. Handle generic asset references (asset_id and asset_type)
  3. Maintain backward compatibility where possible
  4. Continue to properly validate all inputs

Goals

  1. Update the REST API endpoint to support optional prompts with asset context
  2. Modify the endpoint to accept asset_id and asset_type instead of specific asset parameters
  3. Update validation to ensure valid combinations of parameters
  4. Maintain backward compatibility with existing clients
  5. Ensure proper error responses for invalid requests

Non-Goals

  1. Changing the endpoint URL or method
  2. Modifying the response format
  3. Adding new authentication/authorization mechanisms
  4. Implementing client-side changes to adapt to the updated API

Technical Design

Component Overview

The REST endpoint for creating chats is implemented in post_chat_route in the file src/routes/rest/routes/chats/post_chat.rs. It:

  1. Receives requests from clients
  2. Extracts the authenticated user from middleware
  3. Deserializes the request body into a ChatCreateNewChat struct
  4. Calls the post_chat_handler with the request
  5. Returns the response wrapped in ApiResponse::JsonData

The updated endpoint will maintain this flow but update the request schema and validation.

graph TD
    A[Client] -->|HTTP POST /chats| B[post_chat_route]
    B -->|Extract| C[AuthenticatedUser]
    B -->|Deserialize| D[ChatCreateNewChatRequest]
    D --> E{Validate Request}
    E -->|Valid| F[post_chat_handler]
    E -->|Invalid| G[Error Response]
    F --> H[ApiResponse::JsonData]
    G --> I[ApiResponse::Error]
    H --> J[Client]
    I --> J

Interfaces

Exposed Interfaces

// REST endpoint handler
pub async fn post_chat_route(
    Extension(user): Extension<AuthenticatedUser>,
    Json(request): Json<ChatCreateNewChatRequest>,
) -> ApiResponse<ChatWithMessages> {
    // Implementation
}

// Updated request structure
#[derive(Deserialize)]
pub struct ChatCreateNewChatRequest {
    pub prompt: Option<String>,  // Now optional
    pub chat_id: Option<Uuid>,
    pub message_id: Option<Uuid>,
    pub asset_id: Option<Uuid>,
    pub asset_type: Option<AssetType>,
    // Backward compatibility fields (optional)
    pub metric_id: Option<Uuid>,
    pub dashboard_id: Option<Uuid>,
}

Consumed Interfaces

// Handler signature (from handler component)
pub async fn post_chat_handler(
    request: ChatCreateNewChat,
    user: AuthenticatedUser,
    tx: Option<mpsc::Sender<Result<(BusterContainer, ThreadEvent)>>>,
) -> Result<ChatWithMessages> {
    // Implementation in handler component
}

// Conversion to handler request
impl From<ChatCreateNewChatRequest> for ChatCreateNewChat {
    fn from(request: ChatCreateNewChatRequest) -> Self {
        // Implementation
    }
}

Implementation Details

Request Validation and Conversion

// Conversion from API request to handler request
impl From<ChatCreateNewChatRequest> for ChatCreateNewChat {
    fn from(request: ChatCreateNewChatRequest) -> Self {
        // Check for backward compatibility
        let asset_id = if request.asset_id.is_some() {
            request.asset_id
        } else if request.metric_id.is_some() {
            request.metric_id
        } else if request.dashboard_id.is_some() {
            request.dashboard_id
        } else {
            None
        };
        
        let asset_type = if request.asset_type.is_some() {
            request.asset_type
        } else if request.metric_id.is_some() {
            Some(AssetType::MetricFile)
        } else if request.dashboard_id.is_some() {
            Some(AssetType::DashboardFile)
        } else {
            None
        };
        
        Self {
            prompt: request.prompt,
            chat_id: request.chat_id,
            message_id: request.message_id,
            asset_id,
            asset_type,
        }
    }
}

Updated REST Handler

pub async fn post_chat_route(
    Extension(user): Extension<AuthenticatedUser>,
    Json(request): Json<ChatCreateNewChatRequest>,
) -> ApiResponse<ChatWithMessages> {
    // Convert REST request to handler request
    let handler_request: ChatCreateNewChat = request.into();
    
    // Validate parameters
    if handler_request.asset_id.is_some() && handler_request.asset_type.is_none() {
        return ApiResponse::Error(
            StatusCode::BAD_REQUEST,
            "asset_type must be provided when asset_id is specified".to_string(),
        );
    }
    
    // Call handler
    match post_chat_handler(handler_request, user, None).await {
        Ok(response) => ApiResponse::JsonData(response),
        Err(e) => ApiResponse::Error(
            StatusCode::INTERNAL_SERVER_ERROR,
            format!("Failed to create chat: {}", e),
        ),
    }
}

File Changes

Modified Files

  • src/routes/rest/routes/chats/post_chat.rs
    • Changes:
      • Update ChatCreateNewChatRequest struct to make prompt optional
      • Add asset_id and asset_type fields
      • Keep metric_id and dashboard_id for backward compatibility
      • Add conversion from API request to handler request
      • Update validation logic
    • Purpose: REST API endpoint implementation

Testing Strategy

Unit Tests

  • Test ChatCreateNewChatRequest to ChatCreateNewChat conversion

    • Input: Various combinations of prompt, chat_id, asset_id, asset_type, metric_id, and dashboard_id
    • Expected output: Correctly converted handler request
    • Edge cases:
      • Only new fields (asset_id, asset_type)
      • Only old fields (metric_id, dashboard_id)
      • Mix of old and new fields
      • All fields None
  • Test post_chat_route validation

    • Input: Valid and invalid request combinations
    • Expected output: ApiResponse::JsonData or ApiResponse::Error
    • Edge cases:
      • Asset_id without asset_type
      • Invalid asset_type values
      • No prompt but also no asset

Integration Tests

  • Test scenario: Create chat with asset but no prompt

    • Components involved: post_chat_route, post_chat_handler
    • Test steps:
      1. Create request with asset_id, asset_type, but no prompt
      2. Call post_chat_route
      3. Verify response contains expected messages
    • Expected outcome: Chat created with file and text messages
  • Test scenario: Backward compatibility

    • Components involved: post_chat_route, post_chat_handler
    • Test steps:
      1. Create request with metric_id but no asset_id/asset_type
      2. Call post_chat_route
      3. Verify correct conversion and processing
    • Expected outcome: Chat created with metric context
  • Test scenario: Error handling

    • Components involved: post_chat_route, validation
    • Test steps:
      1. Create invalid request (e.g., asset_id without asset_type)
      2. Call post_chat_route
      3. Verify proper error response
    • Expected outcome: Error response with appropriate status code

Security Considerations

  • Validate asset_type to prevent injection attacks
  • Maintain user authentication and authorization checks
  • Ensure proper error messages that don't leak sensitive information
  • Apply rate limiting to prevent abuse

Dependencies on Other Components

Required Components

  • Updated Chat Handler: Requires the handler to support optional prompts and generic assets
  • Asset Type Definitions: Requires valid asset types to be defined

Concurrent Development

  • WebSocket endpoint: Can be updated concurrently
    • Potential conflicts: Request structure and validation logic
    • Mitigation strategy: Use shared validation functions where possible

Implementation Timeline

  • Update request struct: 0.5 days
  • Implement conversion logic: 0.5 days
  • Update validation: 0.5 days
  • Testing: 0.5 days

Total estimated time: 2 days