feat(token): integrate indexer provider#195
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces an alternative "indexer" mode for the token data provider, allowing the system to query balances and total supply via a pre-materialized HTTP API instead of live gRPC scans. Key changes include the implementation of an HTTP client for the indexer, a new indexer-backed provider, and configuration updates to support mode selection. Feedback was provided to improve the robustness of error handling in the indexer client by ensuring that raw response bodies are captured as a fallback when JSON error decoding fails for non-2xx status codes.
| if resp.StatusCode < 200 || resp.StatusCode >= 300 { | ||
| // Best-effort decode of the indexer's JSON error envelope. | ||
| // If the body is not JSON (e.g. an HTML gateway error page), errMsg | ||
| // stays empty and the status code alone is returned to the caller. | ||
| var errMsg string | ||
| var body struct { | ||
| Error string `json:"error"` | ||
| } | ||
| if err := json.NewDecoder(resp.Body).Decode(&body); err == nil { | ||
| errMsg = body.Error | ||
| } | ||
| if resp.StatusCode == http.StatusNotFound { | ||
| return apperrors.ResourceNotFoundError(nil, errMsg) | ||
| } | ||
| return fmt.Errorf("indexer HTTP %d: %s", resp.StatusCode, errMsg) | ||
| } |
There was a problem hiding this comment.
The current error handling for non-2xx responses can hide important debugging information. If the response body isn't a valid JSON with an error field, the error message becomes empty, making it difficult to diagnose issues (e.g., indexer HTTP 500: ).
To make error handling more robust, I suggest reading the entire response body first. You can then use the raw body as a fallback error message if it cannot be parsed as the expected JSON error structure. This ensures a meaningful error message is always available.
Note: You'll need to add "io" to your imports for this change.
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("indexer HTTP %d: failed to read error body: %w", resp.StatusCode, err)
}
var body struct {
Error string `json:"error"`
}
// Default to the full body as the error message.
errMsg := strings.TrimSpace(string(bodyBytes))
// If we can parse the JSON error envelope, use that instead.
if err := json.Unmarshal(bodyBytes, &body); err == nil && body.Error != "" {
errMsg = body.Error
}
if resp.StatusCode == http.StatusNotFound {
return apperrors.ResourceNotFoundError(nil, errMsg)
}
return fmt.Errorf("indexer HTTP %d: %s", resp.StatusCode, errMsg)
}
Closes #192