Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
repos:
- repo: local
hooks:
- id: cargo-fmt
name: cargo fmt
entry: cargo fmt -- --check
language: system
types: [rust]
pass_filenames: false
- id: cargo-clippy
name: cargo clippy (pedantic)
entry: cargo clippy --all-targets --all-features -- -W clippy::pedantic -D warnings
Expand Down
31 changes: 25 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Redash CLI that gives Claude Code direct access to sql.telemetry.mozilla.org —
## Key Constraints

- All clippy::pedantic warnings = errors (pre-commit enforced)
- `cargo fmt` must pass (enforced pre-commit and in CI)
- No docstrings (user preference)
- Borrowed strings preferred (`&str` vs `String`)
- Break complex logic into well-named functions
Expand Down Expand Up @@ -54,6 +55,8 @@ src/
**Data Source**: list_data_sources, get_data_source, get_data_source_schema
**Archive**: archive_query, unarchive_query
**Widget**: create_widget, update_widget, delete_widget
**HTTP**: get_json, post_json
**Errors**: ensure_success

## Testing

Expand All @@ -78,16 +81,32 @@ fn test_something() {
For integration tests needing current directory context, use mutex + TempWorkDir pattern (see `tests/dashboard_commands.rs`).

### API Error Handling
Don't use `.error_for_status()` - it discards the response body. Instead:
Route every response through the `ensure_success` helper in `api.rs`. It returns the
response on success and bails with a uniform `API error {status}: {body}` message
(status `Display` already includes the canonical reason, e.g. `404 Not Found`) on
failure, which helps debugging:

```rust
let status = response.status();
if !status.is_success() {
let error_body = response.text().await.unwrap_or_default();
anyhow::bail!("API error {status}: {error_body}");
}
let response = ensure_success(response).await?;
```

For endpoints that return JSON, achieve this by using `get_json<T>` / `post_json<T, B>`
helpers: they send the request, route it through `ensure_success`, and parse the body
into `T`. The last parameter `ctx` is used for request and parse failure messages
(`Failed to request {ctx}` / `Failed to parse {ctx} response`):

```rust
let response: crate::models::MyResponse =
self.get_json(&url, "my query").await?;

let request: crate::models::MyRequest = ...;
let response: crate::models::MyResponse =
self.post_json(&url, &request, "my query").await?;
```

For wrapper responses, parse into the wrapper type then return the inner field. Endpoints
returning `()` (no body) or needing retries use `ensure_success` / `get_with_retry` directly.

## Redash API Development

**IMPORTANT: Always verify before planning**
Expand Down
Loading
Loading