190 lines
4.9 KiB
Markdown
190 lines
4.9 KiB
Markdown
|
|
# Phase 2 TDD Summary - REST API Implementation
|
||
|
|
|
||
|
|
## 🎯 Current Test Status
|
||
|
|
|
||
|
|
**Total Tests: 17 tests** (12 passing + 5 new API tests)
|
||
|
|
|
||
|
|
### ✅ Passing Tests (14 total)
|
||
|
|
|
||
|
|
**Core Infrastructure (12 tests):**
|
||
|
|
- 3 Auth tests (JWT functionality)
|
||
|
|
- 4 Memory service structure tests
|
||
|
|
- 2 Memory service integration tests
|
||
|
|
- 3 Memory operations tests (placeholders)
|
||
|
|
|
||
|
|
**API Endpoints (2 tests):**
|
||
|
|
- ✅ `test_health_endpoint` - Health check working
|
||
|
|
- ✅ `test_invalid_route_returns_404` - Proper 404 handling
|
||
|
|
|
||
|
|
### ❌ Failing Tests (3 tests) - These Guide Implementation
|
||
|
|
|
||
|
|
**API Endpoints needing implementation:**
|
||
|
|
|
||
|
|
1. **`test_add_fact_endpoint`** - POST /api/facts
|
||
|
|
- **Expected**: Should accept JSON and return 201
|
||
|
|
- **Current**: Returns error (endpoint not implemented)
|
||
|
|
- **Action**: Implement fact creation endpoint
|
||
|
|
|
||
|
|
2. **`test_search_facts_endpoint`** - GET /api/facts/search
|
||
|
|
- **Expected**: Should return search results with 200
|
||
|
|
- **Current**: Returns error (endpoint not implemented)
|
||
|
|
- **Action**: Implement search endpoint
|
||
|
|
|
||
|
|
3. **`test_malformed_json_returns_400`** - Error handling
|
||
|
|
- **Expected**: Should return 400 for bad JSON
|
||
|
|
- **Current**: Returns 404 (wrong error type)
|
||
|
|
- **Action**: Fix error handling middleware
|
||
|
|
|
||
|
|
## 📋 Implementation Plan (TDD-Driven)
|
||
|
|
|
||
|
|
### Step 1: Implement API Handlers
|
||
|
|
|
||
|
|
**Files to create/modify:**
|
||
|
|
```
|
||
|
|
src/api/handlers.rs # Request handlers
|
||
|
|
src/api/rest.rs # REST endpoint definitions
|
||
|
|
```
|
||
|
|
|
||
|
|
**Endpoints to implement:**
|
||
|
|
```rust
|
||
|
|
// POST /api/facts
|
||
|
|
async fn add_fact(
|
||
|
|
service: web::Data<MemoryService>,
|
||
|
|
payload: web::Json<FactRequest>
|
||
|
|
) -> Result<HttpResponse, ServerError> {
|
||
|
|
// TODO: Implement fact creation
|
||
|
|
}
|
||
|
|
|
||
|
|
// GET /api/facts/search
|
||
|
|
async fn search_facts(
|
||
|
|
service: web::Data<MemoryService>,
|
||
|
|
query: web::Query<SearchParams>
|
||
|
|
) -> Result<HttpResponse, ServerError> {
|
||
|
|
// TODO: Implement search
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Step 2: Update API Configuration
|
||
|
|
|
||
|
|
**File: `src/api/config.rs`**
|
||
|
|
```rust
|
||
|
|
pub fn configure_api(cfg: &mut web::ServiceConfig) {
|
||
|
|
cfg.service(
|
||
|
|
web::scope("/api")
|
||
|
|
.route("/health", web::get().to(health_check))
|
||
|
|
.route("/facts", web::post().to(add_fact))
|
||
|
|
.route("/facts/search", web::get().to(search_facts))
|
||
|
|
);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Step 3: Implement Request/Response Types
|
||
|
|
|
||
|
|
**File: `src/api/types.rs` (new)**
|
||
|
|
```rust
|
||
|
|
use serde::{Deserialize, Serialize};
|
||
|
|
|
||
|
|
#[derive(Deserialize)]
|
||
|
|
pub struct FactRequest {
|
||
|
|
pub namespace: String,
|
||
|
|
pub content: String,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Deserialize)]
|
||
|
|
pub struct SearchParams {
|
||
|
|
pub q: String,
|
||
|
|
pub limit: Option<usize>,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Serialize)]
|
||
|
|
pub struct FactResponse {
|
||
|
|
pub id: String,
|
||
|
|
pub namespace: String,
|
||
|
|
pub content: String,
|
||
|
|
pub created_at: String,
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Step 4: Implement Memory Service Operations
|
||
|
|
|
||
|
|
**File: `src/memory/service.rs` (expand)**
|
||
|
|
```rust
|
||
|
|
impl MemoryService {
|
||
|
|
// ... existing code ...
|
||
|
|
|
||
|
|
pub async fn add_fact(
|
||
|
|
&self,
|
||
|
|
namespace: &str,
|
||
|
|
content: &str
|
||
|
|
) -> Result<Fact> {
|
||
|
|
let store = self.get_store();
|
||
|
|
// TODO: Use semantic-memory to add fact
|
||
|
|
}
|
||
|
|
|
||
|
|
pub async fn search_facts(
|
||
|
|
&self,
|
||
|
|
query: &str,
|
||
|
|
limit: usize
|
||
|
|
) -> Result<Vec<Fact>> {
|
||
|
|
let store = self.get_store();
|
||
|
|
// TODO: Use semantic-memory to search
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Step 5: Fix Error Handling
|
||
|
|
|
||
|
|
**File: `src/error.rs` (expand)**
|
||
|
|
```rust
|
||
|
|
impl From<actix_web::error::JsonPayloadError> for ServerError {
|
||
|
|
fn from(err: actix_web::error::JsonPayloadError) -> Self {
|
||
|
|
ServerError::ApiError(err.to_string())
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 🎯 Expected Test Results After Implementation
|
||
|
|
|
||
|
|
| Test | Current Status | Expected Status |
|
||
|
|
|------|---------------|-----------------|
|
||
|
|
| `test_health_endpoint` | ✅ PASS | ✅ PASS |
|
||
|
|
| `test_invalid_route_returns_404` | ✅ PASS | ✅ PASS |
|
||
|
|
| `test_add_fact_endpoint` | ❌ FAIL | ✅ PASS |
|
||
|
|
| `test_search_facts_endpoint` | ❌ FAIL | ✅ PASS |
|
||
|
|
| `test_malformed_json_returns_400` | ❌ FAIL | ✅ PASS |
|
||
|
|
|
||
|
|
**Final: 5/5 API tests passing**
|
||
|
|
|
||
|
|
## 🚀 Next Steps
|
||
|
|
|
||
|
|
1. **Implement API handlers** in `src/api/handlers.rs`
|
||
|
|
2. **Update API routing** in `src/api/config.rs`
|
||
|
|
3. **Add request/response types** in `src/api/types.rs`
|
||
|
|
4. **Expand memory service operations**
|
||
|
|
5. **Fix error handling** for JSON parsing
|
||
|
|
6. **Run tests** to verify implementation
|
||
|
|
|
||
|
|
## 📁 Files to Create/Modify
|
||
|
|
|
||
|
|
```
|
||
|
|
📁 src/api/
|
||
|
|
├── types.rs # NEW: Request/Response types
|
||
|
|
├── handlers.rs # NEW: API handlers
|
||
|
|
└── config.rs # MODIFY: Add new routes
|
||
|
|
|
||
|
|
📁 src/memory/
|
||
|
|
└── service.rs # MODIFY: Add operations
|
||
|
|
|
||
|
|
📁 src/
|
||
|
|
└── error.rs # MODIFY: Add error conversions
|
||
|
|
```
|
||
|
|
|
||
|
|
## ✅ TDD Compliance
|
||
|
|
|
||
|
|
- **Tests written first** ✅
|
||
|
|
- **Tests describe expected behavior** ✅
|
||
|
|
- **Failing tests guide implementation** ✅
|
||
|
|
- **Clear implementation path** ✅
|
||
|
|
- **All tests will remain permanent** ✅
|
||
|
|
|
||
|
|
The failing tests perfectly illustrate the TDD process - they tell us exactly what functionality is missing and what the expected behavior should be.
|