Skip to content

API client cleanup + cargo fmt enforcement - #17

Merged
JohanLorenzo merged 3 commits into
mozilla:mainfrom
yjugl:refactoring
Jun 25, 2026
Merged

JohanLorenzo merged 3 commits into
mozilla:mainfrom
yjugl:refactoring

Conversation

@yjugl

@yjugl yjugl commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

This branch refactors the Redash API client (src/api.rs) to remove duplicated request/error-handling boilerplate, and tightens the developer tooling.

1. Make API error handling uniform (9d55eb1)

Every API method previously inlined its own error-status check, and they had drifted: some used .error_for_status() with the generic context "API returned error status", others hand-rolled anyhow::bail!("HTTP {status}: ..."), some included the response body and some didn't. The messages were inconsistent and several discarded the server's error body — the most useful part for debugging.

All of these are replaced by a single helper:

async fn ensure_success(response: reqwest::Response) -> Result<reqwest::Response> {
    let status = response.status();
    if !status.is_success() {
        let body = response.text().await.unwrap_or_default();
        anyhow::bail!("API error {status}: {body}");
    }
    Ok(response)
}

Why it's beneficial:

  • One uniform error format (API error {status}: {body}) across the whole client, always including the server body.
  • status already Displays the canonical reason (e.g. 404 Not Found), so no manual reason lookup.
  • The retry loop (get_with_retry) now routes through the same helper instead of duplicating the check.
  • Net −159 lines in src/api.rs.

2. Introduce get_json and post_json helpers (8676e93)

Builds on the uniform error handling. Most methods followed the identical shape: build URL → send → ensure_success → .json() → context-wrapped parse. Two generic helpers capture this:

async fn get_json<T: DeserializeOwned>(&self, url: &str, ctx: &str) -> Result<T>
async fn post_json<T: DeserializeOwned, B: Serialize + ?Sized>(&self, url: &str, body: &B, ctx: &str) -> Result<T>

Methods collapse to a URL plus a one-line call, e.g.:

pub async fn get_query(&self, query_id: u64) -> Result<Query> {
    let url = format!("{}/api/queries/{query_id}", self.base_url);
    self.get_json(&url, &format!("query {query_id}")).await
}

Why it's beneficial:

  • Removes ~262 lines of repeated send/check/parse boilerplate.
  • A single ctx string drives both failure messages (Failed to request {ctx} / Failed to parse {ctx} response), keeping request and parse errors consistent.
  • New endpoints become trivial to add and hard to get wrong; methods needing () responses or retries still use ensure_success / get_with_retry directly.

3. Enforce cargo fmt on developer side (e2e66ee)

Adds a cargo fmt -- --check pre-commit hook alongside the existing clippy hook.

Why it's beneficial:

  • cargo fmt was already enforced in CI; this catches formatting issues locally before push, avoiding round-trip CI failures.
  • Keeps developer-side and CI checks in sync.

Notes

  • Pure refactor + tooling — no behavioral change beyond more consistent, more informative error messages.
  • CLAUDE.md is updated in each commit to document the new helpers and the cargo fmt constraint.
  • Combined diff removes well over 400 lines from src/api.rs.

@yjugl
yjugl requested a review from JohanLorenzo as a code owner June 25, 2026 11:21

@JohanLorenzo JohanLorenzo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for centralizing these 2 behaviors! LGTM 👌

@JohanLorenzo
JohanLorenzo merged commit a1294de into mozilla:main Jun 25, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants