mirror of https://github.com/buster-so/buster.git
267 lines
8.5 KiB
Markdown
267 lines
8.5 KiB
Markdown
|
---
|
||
|
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<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
|
||
|
|
||
|
```rust
|
||
|
// 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
|
||
|
|
||
|
```rust
|
||
|
// 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
|
||
|
|
||
|
```rust
|
||
|
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
|