167 lines
3.4 KiB
Markdown
167 lines
3.4 KiB
Markdown
|
|
# Backend API Specification: Calculation Engine
|
||
|
|
|
||
|
|
## Overview
|
||
|
|
Endpoint to evaluate calculated test formulas and return computed values with proper rounding and error handling.
|
||
|
|
|
||
|
|
## Endpoint
|
||
|
|
|
||
|
|
```
|
||
|
|
POST /api/calculate/evaluate
|
||
|
|
```
|
||
|
|
|
||
|
|
## Request Body
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
{
|
||
|
|
// The formula expression using test codes as variables
|
||
|
|
// Example: "CHOL - HDL - (TG/5)"
|
||
|
|
formula: string;
|
||
|
|
|
||
|
|
// Map of test codes to their current numeric values
|
||
|
|
// Example: { "CHOL": 180, "HDL": 45, "TG": 150 }
|
||
|
|
values: Record<string, number>;
|
||
|
|
|
||
|
|
// Decimal precision for rounding (0-6)
|
||
|
|
// Default: 2
|
||
|
|
decimal?: number;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Response Body
|
||
|
|
|
||
|
|
### Success (200)
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
{
|
||
|
|
status: "success";
|
||
|
|
data: {
|
||
|
|
// The computed result value
|
||
|
|
result: number;
|
||
|
|
|
||
|
|
// The result rounded to specified decimal places
|
||
|
|
resultRounded: number;
|
||
|
|
|
||
|
|
// Formula that was evaluated (for verification)
|
||
|
|
evaluatedFormula: string;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Error (400/422)
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
{
|
||
|
|
status: "error";
|
||
|
|
message: string;
|
||
|
|
error: {
|
||
|
|
// Error type for frontend handling
|
||
|
|
type: "MISSING_VALUE" | "INVALID_EXPRESSION" | "DIVISION_BY_ZERO" | "SYNTAX_ERROR";
|
||
|
|
|
||
|
|
// Missing variable names if applicable
|
||
|
|
missingVars?: string[];
|
||
|
|
|
||
|
|
// Position of syntax error if applicable
|
||
|
|
position?: number;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Formula Syntax
|
||
|
|
|
||
|
|
### Supported Operators
|
||
|
|
- Arithmetic: `+`, `-`, `*`, `/`, `^` (power)
|
||
|
|
- Parentheses: `(` `)` for grouping
|
||
|
|
- Functions: `abs()`, `round()`, `floor()`, `ceil()`, `min()`, `max()`, `sqrt()`
|
||
|
|
|
||
|
|
### Variable Names
|
||
|
|
- Test codes are used as variable names directly
|
||
|
|
- Case-sensitive (CHOL ≠ chol)
|
||
|
|
- Must match exactly (word boundaries)
|
||
|
|
|
||
|
|
### Examples
|
||
|
|
|
||
|
|
**Simple subtraction:**
|
||
|
|
```
|
||
|
|
Formula: "CHOL - HDL"
|
||
|
|
Values: { "CHOL": 180, "HDL": 45 }
|
||
|
|
Result: 135
|
||
|
|
```
|
||
|
|
|
||
|
|
**Complex with division:**
|
||
|
|
```
|
||
|
|
Formula: "CHOL - HDL - (TG/5)"
|
||
|
|
Values: { "CHOL": 180, "HDL": 45, "TG": 150 }
|
||
|
|
Result: 105
|
||
|
|
```
|
||
|
|
|
||
|
|
**With decimal rounding:**
|
||
|
|
```
|
||
|
|
Formula: "(HGB * MCV) / 100"
|
||
|
|
Values: { "HGB": 14.2, "MCV": 87.5 }
|
||
|
|
Decimal: 2
|
||
|
|
Result: 12.43
|
||
|
|
```
|
||
|
|
|
||
|
|
## Validation Rules
|
||
|
|
|
||
|
|
1. **Missing Values**: If any variable in formula is not provided in values, return MISSING_VALUE error
|
||
|
|
2. **Division by Zero**: Return DIVISION_BY_ZERO error if encountered
|
||
|
|
3. **Invalid Syntax**: Return SYNTAX_ERROR with position if formula cannot be parsed
|
||
|
|
4. **Non-numeric Values**: Return MISSING_VALUE if any value is not a valid number
|
||
|
|
|
||
|
|
## Batch Endpoint (Optional)
|
||
|
|
|
||
|
|
For efficiency when recalculating multiple CALC tests:
|
||
|
|
|
||
|
|
```
|
||
|
|
POST /api/calculate/evaluate-batch
|
||
|
|
```
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// Request
|
||
|
|
{
|
||
|
|
calculations: [
|
||
|
|
{
|
||
|
|
testSiteId: number;
|
||
|
|
formula: string;
|
||
|
|
values: Record<string, number>;
|
||
|
|
decimal?: number;
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
|
||
|
|
// Response
|
||
|
|
{
|
||
|
|
status: "success";
|
||
|
|
data: {
|
||
|
|
results: [
|
||
|
|
{
|
||
|
|
testSiteId: number;
|
||
|
|
result: number;
|
||
|
|
resultRounded: number;
|
||
|
|
error?: {
|
||
|
|
type: string;
|
||
|
|
message: string;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Frontend Integration
|
||
|
|
|
||
|
|
The frontend will:
|
||
|
|
1. Build dependency graph from test definitions
|
||
|
|
2. Detect when member test values change
|
||
|
|
3. Call this API to compute dependent CALC tests
|
||
|
|
4. Update UI with computed values
|
||
|
|
5. Mark CALC tests as `changedByAutoCalc` for save tracking
|
||
|
|
|
||
|
|
## Security Considerations
|
||
|
|
|
||
|
|
1. Never use `eval()` or similar unsafe evaluation
|
||
|
|
2. Use a proper expression parser (mathjs, muparser, or custom parser)
|
||
|
|
3. Sanitize/validate formula input before parsing
|
||
|
|
4. Limit computation time to prevent DoS
|