1+ using Microsoft . Extensions . Logging ;
2+ using System . Collections ;
3+ using System . Net . Http . Json ;
4+ using System . Text . Json ;
5+
6+ // Create a base class for all AFL tools
7+ public abstract class BaseAFLTool
8+ {
9+ protected readonly HttpClient _httpClient ;
10+ protected readonly ILogger _logger ;
11+
12+ protected BaseAFLTool ( HttpClient httpClient , ILogger logger )
13+ {
14+ _httpClient = httpClient ?? throw new ArgumentNullException ( nameof ( httpClient ) ) ;
15+ _logger = logger ?? throw new ArgumentNullException ( nameof ( logger ) ) ;
16+ }
17+
18+ /// <summary>
19+ /// Executes an API call with standardized error handling and logging
20+ /// </summary>
21+ /// <typeparam name="T">The type to deserialize the result to</typeparam>
22+ /// <param name="endpoint">The API endpoint to call</param>
23+ /// <param name="operationName">A descriptive name for logging purposes</param>
24+ /// <param name="propertyName">The JSON property name to extract from the response</param>
25+ /// <param name="additionalValidation">Optional additional validation function</param>
26+ /// <returns>The deserialized result or default(T) on error</returns>
27+ protected async Task < T > ExecuteApiCallAsync < T > (
28+ string endpoint ,
29+ string operationName ,
30+ string propertyName ,
31+ Func < T , bool > additionalValidation = null ) where T : class , new ( )
32+ {
33+ _logger . LogInformation ( "Fetching data for {Operation} - Endpoint: {Endpoint}" , operationName , endpoint ) ;
34+
35+ try
36+ {
37+ var response = await _httpClient . GetAsync ( endpoint ) ;
38+
39+ if ( ! response . IsSuccessStatusCode )
40+ {
41+ _logger . LogError ( "API request failed. StatusCode: {StatusCode}, Endpoint: {Endpoint}" ,
42+ response . StatusCode , endpoint ) ;
43+ return new T ( ) ;
44+ }
45+
46+ var jsonElement = await response . Content . ReadFromJsonAsync < JsonElement > ( ) ;
47+
48+ if ( ! jsonElement . TryGetProperty ( propertyName , out var property ) )
49+ {
50+ _logger . LogWarning ( "No '{PropertyName}' property found in API response for {Operation}" ,
51+ propertyName , operationName ) ;
52+ return new T ( ) ;
53+ }
54+
55+ var result = JsonSerializer . Deserialize < T > ( property . GetRawText ( ) ) ;
56+
57+ if ( result == null )
58+ {
59+ _logger . LogWarning ( "Failed to deserialize response for {Operation}" , operationName ) ;
60+ return new T ( ) ;
61+ }
62+
63+ // Check if result is a collection and log appropriately
64+ if ( result is ICollection collection )
65+ {
66+ if ( collection . Count == 0 )
67+ {
68+ _logger . LogInformation ( "No data found for {Operation}" , operationName ) ;
69+ }
70+ else
71+ {
72+ _logger . LogInformation ( "Successfully retrieved {Count} items for {Operation}" ,
73+ collection . Count , operationName ) ;
74+ }
75+ }
76+ else
77+ {
78+ _logger . LogInformation ( "Successfully retrieved data for {Operation}" , operationName ) ;
79+ }
80+
81+ // Run additional validation if provided
82+ if ( additionalValidation != null && ! additionalValidation ( result ) )
83+ {
84+ _logger . LogWarning ( "Additional validation failed for {Operation}" , operationName ) ;
85+ return new T ( ) ;
86+ }
87+
88+ return result ;
89+ }
90+ catch ( HttpRequestException ex )
91+ {
92+ _logger . LogError ( ex , "Network error for {Operation}" , operationName ) ;
93+ return new T ( ) ;
94+ }
95+ catch ( TaskCanceledException ex )
96+ {
97+ _logger . LogError ( ex , "Timeout for {Operation}" , operationName ) ;
98+ return new T ( ) ;
99+ }
100+ catch ( JsonException ex )
101+ {
102+ _logger . LogError ( ex , "JSON parsing error for {Operation}" , operationName ) ;
103+ return new T ( ) ;
104+ }
105+ catch ( Exception ex )
106+ {
107+ _logger . LogError ( ex , "Unexpected error for {Operation}" , operationName ) ;
108+ return new T ( ) ;
109+ }
110+ }
111+
112+ /// <summary>
113+ /// Validates input parameters and logs warnings for invalid values
114+ /// </summary>
115+ protected bool ValidateParameters ( params ( string name , object value , Func < object , bool > validator , string errorMessage ) [ ] validations )
116+ {
117+ foreach ( var ( name , value , validator , errorMessage ) in validations )
118+ {
119+ if ( ! validator ( value ) )
120+ {
121+ _logger . LogWarning ( "Invalid {ParameterName} parameter: {Value}. {ErrorMessage}" , name , value , errorMessage ) ;
122+ return false ;
123+ }
124+ }
125+ return true ;
126+ }
127+
128+ // Common validation methods
129+ protected static bool IsValidYear ( int year ) => year >= 1897 && year <= DateTime . Now . Year + 1 ;
130+ protected static bool IsValidRound ( int round ) => round >= 1 && round <= 30 ;
131+ protected static bool IsValidId ( int id ) => id > 0 ;
132+ protected static bool IsValidString ( string value ) => ! string . IsNullOrWhiteSpace ( value ) ;
133+ }
0 commit comments