172 lines
5.8 KiB
Python
172 lines
5.8 KiB
Python
"""
|
|
Response formatter for API responses.
|
|
"""
|
|
|
|
from typing import Any, Dict, Optional
|
|
from datetime import datetime
|
|
|
|
|
|
class ResponseFormatter:
|
|
"""Format API responses consistently"""
|
|
|
|
def __init__(self):
|
|
self.stats = {
|
|
'responses_formatted': 0,
|
|
'errors_formatted': 0,
|
|
'success_responses': 0,
|
|
'created_at': datetime.utcnow().isoformat()
|
|
}
|
|
|
|
def success(self, data: Any, message: str = "Success", metadata: Optional[Dict] = None) -> Dict[str, Any]:
|
|
"""Format success response"""
|
|
self.stats['responses_formatted'] += 1
|
|
self.stats['success_responses'] += 1
|
|
|
|
response = {
|
|
"status": "success",
|
|
"message": message,
|
|
"data": data,
|
|
"timestamp": datetime.utcnow().isoformat()
|
|
}
|
|
|
|
if metadata:
|
|
response["metadata"] = metadata
|
|
|
|
return response
|
|
|
|
def error(self, message: str, code: str = "ERROR", details: Optional[Dict] = None) -> Dict[str, Any]:
|
|
"""Format error response"""
|
|
self.stats['responses_formatted'] += 1
|
|
self.stats['errors_formatted'] += 1
|
|
|
|
response = {
|
|
"status": "error",
|
|
"message": message,
|
|
"code": code,
|
|
"timestamp": datetime.utcnow().isoformat()
|
|
}
|
|
|
|
if details:
|
|
response["details"] = details
|
|
|
|
return response
|
|
|
|
def health(self, healthy: bool = True, components: Optional[Dict] = None) -> Dict[str, Any]:
|
|
"""Format health check response"""
|
|
self.stats['responses_formatted'] += 1
|
|
|
|
return {
|
|
"status": "healthy" if healthy else "unhealthy",
|
|
"timestamp": datetime.utcnow().isoformat(),
|
|
"components": components or {}
|
|
}
|
|
|
|
def rate_limit_error(self, client_stats: Dict) -> Dict[str, Any]:
|
|
"""Format rate limit error response"""
|
|
self.stats['responses_formatted'] += 1
|
|
self.stats['errors_formatted'] += 1
|
|
|
|
return {
|
|
"status": "error",
|
|
"message": "Rate limit exceeded",
|
|
"code": "RATE_LIMIT_EXCEEDED",
|
|
"timestamp": datetime.utcnow().isoformat(),
|
|
"details": {
|
|
"remaining_tokens": client_stats.get('remaining_tokens', 0),
|
|
"reset_time": client_stats.get('reset_time', 0),
|
|
"requests_per_minute": client_stats.get('requests_per_minute', 0)
|
|
}
|
|
}
|
|
|
|
def validation_error(self, field: str, message: str) -> Dict[str, Any]:
|
|
"""Format validation error response"""
|
|
self.stats['responses_formatted'] += 1
|
|
self.stats['errors_formatted'] += 1
|
|
|
|
return {
|
|
"status": "error",
|
|
"message": f"Validation error: {message}",
|
|
"code": "VALIDATION_ERROR",
|
|
"timestamp": datetime.utcnow().isoformat(),
|
|
"details": {
|
|
"field": field,
|
|
"validation_message": message
|
|
}
|
|
}
|
|
|
|
def status_response(self, data: Dict) -> Dict[str, Any]:
|
|
"""Format status response"""
|
|
self.stats['responses_formatted'] += 1
|
|
self.stats['success_responses'] += 1
|
|
|
|
return {
|
|
"status": "success",
|
|
"message": "System status",
|
|
"data": data,
|
|
"timestamp": datetime.utcnow().isoformat()
|
|
}
|
|
|
|
def heatmap_response(self, heatmap_data: Any, symbol: str, exchange: Optional[str] = None) -> Dict[str, Any]:
|
|
"""Format heatmap response"""
|
|
self.stats['responses_formatted'] += 1
|
|
self.stats['success_responses'] += 1
|
|
|
|
if not heatmap_data:
|
|
return self.error("Heatmap data not found", "HEATMAP_NOT_FOUND")
|
|
|
|
return {
|
|
"status": "success",
|
|
"message": f"Heatmap data for {symbol}",
|
|
"data": {
|
|
"symbol": symbol,
|
|
"exchange": exchange or "consolidated",
|
|
"heatmap": heatmap_data
|
|
},
|
|
"timestamp": datetime.utcnow().isoformat()
|
|
}
|
|
|
|
def orderbook_response(self, orderbook_data: Any, symbol: str, exchange: str) -> Dict[str, Any]:
|
|
"""Format order book response"""
|
|
self.stats['responses_formatted'] += 1
|
|
self.stats['success_responses'] += 1
|
|
|
|
if not orderbook_data:
|
|
return self.error("Order book data not found", "ORDERBOOK_NOT_FOUND")
|
|
|
|
return {
|
|
"status": "success",
|
|
"message": f"Order book data for {symbol}@{exchange}",
|
|
"data": {
|
|
"symbol": symbol,
|
|
"exchange": exchange,
|
|
"orderbook": orderbook_data
|
|
},
|
|
"timestamp": datetime.utcnow().isoformat()
|
|
}
|
|
|
|
def metrics_response(self, metrics_data: Any, symbol: str, exchange: str) -> Dict[str, Any]:
|
|
"""Format metrics response"""
|
|
self.stats['responses_formatted'] += 1
|
|
self.stats['success_responses'] += 1
|
|
|
|
if not metrics_data:
|
|
return self.error("Metrics data not found", "METRICS_NOT_FOUND")
|
|
|
|
return {
|
|
"status": "success",
|
|
"message": f"Metrics data for {symbol}@{exchange}",
|
|
"data": {
|
|
"symbol": symbol,
|
|
"exchange": exchange,
|
|
"metrics": metrics_data
|
|
},
|
|
"timestamp": datetime.utcnow().isoformat()
|
|
}
|
|
|
|
def get_stats(self) -> Dict[str, Any]:
|
|
"""Get formatter statistics"""
|
|
return {
|
|
**self.stats,
|
|
'uptime_seconds': (datetime.utcnow() - datetime.fromisoformat(self.stats['created_at'])).total_seconds(),
|
|
'error_rate': self.stats['errors_formatted'] / max(1, self.stats['responses_formatted'])
|
|
} |