"""Standardized API response helpers.""" from flask import jsonify, make_response from typing import Any, Dict, List, Optional from datetime import datetime import uuid class ErrorCodes: """Standard error codes.""" VALIDATION_ERROR = 'VALIDATION_ERROR' NOT_FOUND = 'NOT_FOUND' UNAUTHORIZED = 'UNAUTHORIZED' FORBIDDEN = 'FORBIDDEN' CONFLICT = 'CONFLICT' INTERNAL_ERROR = 'INTERNAL_ERROR' BAD_REQUEST = 'BAD_REQUEST' PLUGIN_ERROR = 'PLUGIN_ERROR' def api_response( data: Any = None, message: str = None, status: str = 'success', meta: Dict = None, http_code: int = 200 ): """ Create standardized API response. Response format: { "status": "success" | "error", "data": {...} | [...], "message": "Optional message", "meta": { "timestamp": "2025-01-12T...", "request_id": "uuid" } } """ response = { 'status': status, 'meta': { 'timestamp': datetime.utcnow().isoformat() + 'Z', 'requestid': str(uuid.uuid4())[:8], **(meta or {}) } } if data is not None: response['data'] = data if message: response['message'] = message return make_response(jsonify(response), http_code) def success_response( data: Any = None, message: str = None, meta: Dict = None, http_code: int = 200 ): """Success response helper.""" return api_response( data=data, message=message, meta=meta, status='success', http_code=http_code ) def error_response( code: str, message: str, details: Dict = None, http_code: int = 400 ): """ Error response helper. Response format: { "status": "error", "error": { "code": "VALIDATION_ERROR", "message": "Human-readable message", "details": {...} } } """ error_data = { 'code': code, 'message': message } if details: error_data['details'] = details return api_response( data={'error': error_data}, status='error', http_code=http_code ) def api_error( message: str, code: str = ErrorCodes.BAD_REQUEST, details: Dict = None, http_code: int = 400 ): """ Simplified error response helper. Args: message: Human-readable error message code: Error code (default BAD_REQUEST) details: Optional error details http_code: HTTP status code (default 400) """ return error_response(code=code, message=message, details=details, http_code=http_code) def paginated_response( items: List, page: int, per_page: int, total: int, schema=None ): """ Paginated list response. Response format: { "status": "success", "data": [...], "meta": { "pagination": { "page": 1, "per_page": 20, "total": 150, "total_pages": 8, "has_next": true, "has_prev": false } } } """ total_pages = (total + per_page - 1) // per_page if per_page > 0 else 0 if schema: items = schema.dump(items, many=True) return api_response( data=items, meta={ 'pagination': { 'page': page, 'perpage': per_page, 'total': total, 'totalpages': total_pages, 'hasnext': page < total_pages, 'hasprev': page > 1 } } )