Major Phase 2 Achievements: ✅ Enterprise-grade FastAPI server with comprehensive middleware ✅ JWT and API key authentication systems ✅ Comprehensive Python SDK (sync/async) with advanced features ✅ Multi-language SDK ecosystem (JavaScript/TypeScript, Go, Rust, Java, C#) ✅ OpenAPI/Swagger documentation with PDF generation ✅ WebSocket streaming and real-time updates ✅ Advanced caching systems (LRU, LFU, FIFO, TTL) ✅ Comprehensive error handling hierarchies ✅ Batch operations and high-throughput processing SDK Features Implemented: - Promise-based JavaScript/TypeScript with full type safety - Context-aware Go SDK with goroutine safety - Memory-safe Rust SDK with async/await - Reactive Java SDK with RxJava integration - .NET 6+ C# SDK with dependency injection support - Consistent API design across all languages - Production-ready error handling and caching Documentation & Testing: - Complete OpenAPI specification with interactive docs - Professional Sphinx documentation with ReadTheDocs styling - LaTeX-generated PDF manuals - Comprehensive functional testing across all SDKs - Performance validation and benchmarking Project Status: PRODUCTION-READY - 2 major phases completed on schedule - 5 programming languages with full feature parity - Enterprise features: authentication, caching, streaming, monitoring - Ready for deployment, academic publication, and commercial licensing 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
578 lines
17 KiB
C#
578 lines
17 KiB
C#
using System.ComponentModel.DataAnnotations;
|
|
using System.Text.Json.Serialization;
|
|
|
|
namespace HCFS.SDK;
|
|
|
|
/// <summary>
|
|
/// Base exception for all HCFS SDK errors.
|
|
/// </summary>
|
|
public class HCFSException : Exception
|
|
{
|
|
/// <summary>
|
|
/// Gets the error code associated with this exception.
|
|
/// </summary>
|
|
public string? ErrorCode { get; }
|
|
|
|
/// <summary>
|
|
/// Gets additional error details.
|
|
/// </summary>
|
|
public IReadOnlyDictionary<string, object>? Details { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the HTTP status code if applicable.
|
|
/// </summary>
|
|
public int? StatusCode { get; }
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
public HCFSException(string message) : base(message)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
/// <param name="errorCode">The error code.</param>
|
|
public HCFSException(string message, string errorCode) : base(message)
|
|
{
|
|
ErrorCode = errorCode;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
/// <param name="errorCode">The error code.</param>
|
|
/// <param name="details">Additional error details.</param>
|
|
/// <param name="statusCode">HTTP status code.</param>
|
|
public HCFSException(string message, string? errorCode, IReadOnlyDictionary<string, object>? details, int? statusCode) : base(message)
|
|
{
|
|
ErrorCode = errorCode;
|
|
Details = details;
|
|
StatusCode = statusCode;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
/// <param name="innerException">The inner exception.</param>
|
|
public HCFSException(string message, Exception innerException) : base(message, innerException)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if this error should trigger a retry.
|
|
/// </summary>
|
|
/// <returns>True if the error is retryable.</returns>
|
|
public virtual bool IsRetryable()
|
|
{
|
|
return StatusCode >= 500 || StatusCode == 429 ||
|
|
this is HCFSConnectionException ||
|
|
this is HCFSTimeoutException;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if this error is temporary.
|
|
/// </summary>
|
|
/// <returns>True if the error is temporary.</returns>
|
|
public virtual bool IsTemporary()
|
|
{
|
|
return StatusCode == 429 || StatusCode == 502 || StatusCode == 503 || StatusCode == 504 ||
|
|
this is HCFSTimeoutException ||
|
|
this is HCFSConnectionException;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Thrown when connection to HCFS API fails.
|
|
/// </summary>
|
|
public class HCFSConnectionException : HCFSException
|
|
{
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSConnectionException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
public HCFSConnectionException(string message = "Failed to connect to HCFS API")
|
|
: base(message, "CONNECTION_FAILED")
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSConnectionException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
/// <param name="innerException">The inner exception.</param>
|
|
public HCFSConnectionException(string message, Exception innerException)
|
|
: base(message, innerException)
|
|
{
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Thrown when authentication fails.
|
|
/// </summary>
|
|
public class HCFSAuthenticationException : HCFSException
|
|
{
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSAuthenticationException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
public HCFSAuthenticationException(string message = "Authentication failed")
|
|
: base(message, "AUTH_FAILED", null, 401)
|
|
{
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Thrown when user lacks permissions for an operation.
|
|
/// </summary>
|
|
public class HCFSAuthorizationException : HCFSException
|
|
{
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSAuthorizationException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
public HCFSAuthorizationException(string message = "Insufficient permissions")
|
|
: base(message, "INSUFFICIENT_PERMISSIONS", null, 403)
|
|
{
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Thrown when a requested resource is not found.
|
|
/// </summary>
|
|
public class HCFSNotFoundException : HCFSException
|
|
{
|
|
/// <summary>
|
|
/// Gets the type of resource that was not found.
|
|
/// </summary>
|
|
public string? ResourceType { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the ID of the resource that was not found.
|
|
/// </summary>
|
|
public string? ResourceId { get; }
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSNotFoundException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
public HCFSNotFoundException(string message = "Resource not found")
|
|
: base(message, "NOT_FOUND", null, 404)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSNotFoundException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
/// <param name="resourceType">The type of resource.</param>
|
|
/// <param name="resourceId">The resource ID.</param>
|
|
public HCFSNotFoundException(string message, string? resourceType, string? resourceId)
|
|
: base(message, "NOT_FOUND", null, 404)
|
|
{
|
|
ResourceType = resourceType;
|
|
ResourceId = resourceId;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the error message with resource details.
|
|
/// </summary>
|
|
public override string Message
|
|
{
|
|
get
|
|
{
|
|
var message = base.Message;
|
|
if (!string.IsNullOrEmpty(ResourceType))
|
|
{
|
|
message += $" (type: {ResourceType})";
|
|
}
|
|
if (!string.IsNullOrEmpty(ResourceId))
|
|
{
|
|
message += $" (id: {ResourceId})";
|
|
}
|
|
return message;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Thrown when request validation fails.
|
|
/// </summary>
|
|
public class HCFSValidationException : ValidationException
|
|
{
|
|
/// <summary>
|
|
/// Gets the validation error details.
|
|
/// </summary>
|
|
public IReadOnlyList<ValidationErrorDetail>? ValidationErrors { get; }
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSValidationException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
public HCFSValidationException(string message = "Request validation failed") : base(message)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSValidationException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
/// <param name="validationErrors">The validation error details.</param>
|
|
public HCFSValidationException(string message, IReadOnlyList<ValidationErrorDetail> validationErrors)
|
|
: base(message)
|
|
{
|
|
ValidationErrors = validationErrors;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the error message with validation details.
|
|
/// </summary>
|
|
public override string Message
|
|
{
|
|
get
|
|
{
|
|
var message = base.Message;
|
|
if (ValidationErrors != null && ValidationErrors.Count > 0)
|
|
{
|
|
message += $" ({ValidationErrors.Count} validation issues)";
|
|
}
|
|
return message;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validation error detail.
|
|
/// </summary>
|
|
public record ValidationErrorDetail
|
|
{
|
|
/// <summary>
|
|
/// Gets the field name that failed validation.
|
|
/// </summary>
|
|
[JsonPropertyName("field")]
|
|
public string? Field { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the validation error message.
|
|
/// </summary>
|
|
[JsonPropertyName("message")]
|
|
public string Message { get; init; } = string.Empty;
|
|
|
|
/// <summary>
|
|
/// Gets the validation error code.
|
|
/// </summary>
|
|
[JsonPropertyName("code")]
|
|
public string? Code { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Thrown when rate limit is exceeded.
|
|
/// </summary>
|
|
public class HCFSRateLimitException : HCFSException
|
|
{
|
|
/// <summary>
|
|
/// Gets the time to wait before retrying.
|
|
/// </summary>
|
|
public double? RetryAfterSeconds { get; }
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSRateLimitException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
public HCFSRateLimitException(string message = "Rate limit exceeded")
|
|
: base(message, "RATE_LIMIT_EXCEEDED", null, 429)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSRateLimitException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
/// <param name="retryAfterSeconds">Seconds to wait before retrying.</param>
|
|
public HCFSRateLimitException(string message, double? retryAfterSeconds)
|
|
: base(BuildMessage(message, retryAfterSeconds), "RATE_LIMIT_EXCEEDED", null, 429)
|
|
{
|
|
RetryAfterSeconds = retryAfterSeconds;
|
|
}
|
|
|
|
private static string BuildMessage(string message, double? retryAfterSeconds)
|
|
{
|
|
if (retryAfterSeconds.HasValue)
|
|
{
|
|
return $"{message}. Retry after {retryAfterSeconds.Value} seconds";
|
|
}
|
|
return message;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Thrown for server-side errors (5xx status codes).
|
|
/// </summary>
|
|
public class HCFSServerException : HCFSException
|
|
{
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSServerException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
/// <param name="statusCode">The HTTP status code.</param>
|
|
public HCFSServerException(string message = "Internal server error", int statusCode = 500)
|
|
: base(message, "SERVER_ERROR", null, statusCode)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the error message with status code.
|
|
/// </summary>
|
|
public override string Message => $"Server error (HTTP {StatusCode}): {base.Message}";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Thrown when a request times out.
|
|
/// </summary>
|
|
public class HCFSTimeoutException : HCFSException
|
|
{
|
|
/// <summary>
|
|
/// Gets the timeout duration that was exceeded.
|
|
/// </summary>
|
|
public TimeSpan? Timeout { get; }
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSTimeoutException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
public HCFSTimeoutException(string message = "Request timed out")
|
|
: base(message, "TIMEOUT")
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSTimeoutException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
/// <param name="timeout">The timeout duration.</param>
|
|
public HCFSTimeoutException(string message, TimeSpan timeout)
|
|
: base($"{message} after {timeout.TotalMilliseconds}ms", "TIMEOUT")
|
|
{
|
|
Timeout = timeout;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Thrown for cache-related errors.
|
|
/// </summary>
|
|
public class HCFSCacheException : HCFSException
|
|
{
|
|
/// <summary>
|
|
/// Gets the cache operation that failed.
|
|
/// </summary>
|
|
public string? Operation { get; }
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSCacheException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
public HCFSCacheException(string message = "Cache operation failed")
|
|
: base(message, "CACHE_ERROR")
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSCacheException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
/// <param name="operation">The cache operation.</param>
|
|
public HCFSCacheException(string message, string operation)
|
|
: base(message, "CACHE_ERROR")
|
|
{
|
|
Operation = operation;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the error message with operation details.
|
|
/// </summary>
|
|
public override string Message
|
|
{
|
|
get
|
|
{
|
|
if (!string.IsNullOrEmpty(Operation))
|
|
{
|
|
return $"Cache error during {Operation}: {base.Message}";
|
|
}
|
|
return $"Cache error: {base.Message}";
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Thrown for batch operation errors.
|
|
/// </summary>
|
|
public class HCFSBatchException : HCFSException
|
|
{
|
|
/// <summary>
|
|
/// Gets the items that failed in the batch operation.
|
|
/// </summary>
|
|
public IReadOnlyList<BatchFailureItem>? FailedItems { get; }
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSBatchException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
public HCFSBatchException(string message = "Batch operation failed")
|
|
: base(message, "BATCH_ERROR")
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSBatchException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
/// <param name="failedItems">The failed items.</param>
|
|
public HCFSBatchException(string message, IReadOnlyList<BatchFailureItem> failedItems)
|
|
: base(message, "BATCH_ERROR")
|
|
{
|
|
FailedItems = failedItems;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the error message with failure details.
|
|
/// </summary>
|
|
public override string Message
|
|
{
|
|
get
|
|
{
|
|
var message = base.Message;
|
|
if (FailedItems != null && FailedItems.Count > 0)
|
|
{
|
|
message += $" ({FailedItems.Count} failed items)";
|
|
}
|
|
return message;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Batch operation failure item.
|
|
/// </summary>
|
|
public record BatchFailureItem
|
|
{
|
|
/// <summary>
|
|
/// Gets the index of the failed item.
|
|
/// </summary>
|
|
[JsonPropertyName("index")]
|
|
public int Index { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the error message for the failed item.
|
|
/// </summary>
|
|
[JsonPropertyName("error")]
|
|
public string Error { get; init; } = string.Empty;
|
|
|
|
/// <summary>
|
|
/// Gets the item data that failed.
|
|
/// </summary>
|
|
[JsonPropertyName("item")]
|
|
public object? Item { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Thrown for search operation errors.
|
|
/// </summary>
|
|
public class HCFSSearchException : HCFSException
|
|
{
|
|
/// <summary>
|
|
/// Gets the search query that failed.
|
|
/// </summary>
|
|
public string? Query { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the search type that was used.
|
|
/// </summary>
|
|
public string? SearchType { get; }
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSSearchException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
public HCFSSearchException(string message = "Search failed")
|
|
: base(message, "SEARCH_ERROR")
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSSearchException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
/// <param name="query">The search query.</param>
|
|
/// <param name="searchType">The search type.</param>
|
|
public HCFSSearchException(string message, string? query, string? searchType)
|
|
: base(message, "SEARCH_ERROR")
|
|
{
|
|
Query = query;
|
|
SearchType = searchType;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the error message with search details.
|
|
/// </summary>
|
|
public override string Message
|
|
{
|
|
get
|
|
{
|
|
var message = $"Search error: {base.Message}";
|
|
if (!string.IsNullOrEmpty(SearchType))
|
|
{
|
|
message += $" (type: {SearchType})";
|
|
}
|
|
if (!string.IsNullOrEmpty(Query))
|
|
{
|
|
message += $" (query: '{Query}')";
|
|
}
|
|
return message;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Thrown for streaming/WebSocket errors.
|
|
/// </summary>
|
|
public class HCFSStreamException : HCFSException
|
|
{
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSStreamException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
public HCFSStreamException(string message = "Stream operation failed")
|
|
: base(message, "STREAM_ERROR")
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="HCFSStreamException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message.</param>
|
|
/// <param name="innerException">The inner exception.</param>
|
|
public HCFSStreamException(string message, Exception innerException)
|
|
: base(message, innerException)
|
|
{
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Error response from the API.
|
|
/// </summary>
|
|
internal record ApiErrorResponse
|
|
{
|
|
[JsonPropertyName("error")]
|
|
public string? Error { get; init; }
|
|
|
|
[JsonPropertyName("message")]
|
|
public string? Message { get; init; }
|
|
|
|
[JsonPropertyName("details")]
|
|
public Dictionary<string, object>? Details { get; init; }
|
|
} |