--- title: REST Post Chat Endpoint Implementation author: Dallin date: 2025-03-21 status: Draft parent_prd: optional_prompt_asset_chat.md --- # REST Post Chat Endpoint Implementation ## Parent Project This is a sub-PRD of the [Optional Prompt Asset Chat System](optional_prompt_asset_chat.md) 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. ```mermaid 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 ```rust // REST endpoint handler pub async fn post_chat_route( Extension(user): Extension, Json(request): Json, ) -> ApiResponse { // Implementation } // Updated request structure #[derive(Deserialize)] pub struct ChatCreateNewChatRequest { pub prompt: Option, // Now optional pub chat_id: Option, pub message_id: Option, pub asset_id: Option, pub asset_type: Option, // Backward compatibility fields (optional) pub metric_id: Option, pub dashboard_id: Option, } ``` #### Consumed Interfaces ```rust // Handler signature (from handler component) pub async fn post_chat_handler( request: ChatCreateNewChat, user: AuthenticatedUser, tx: Option>>, ) -> Result { // Implementation in handler component } // Conversion to handler request impl From for ChatCreateNewChat { fn from(request: ChatCreateNewChatRequest) -> Self { // Implementation } } ``` ### Implementation Details #### Request Validation and Conversion ```rust // Conversion from API request to handler request impl From 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 ```rust pub async fn post_chat_route( Extension(user): Extension, Json(request): Json, ) -> ApiResponse { // 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