hevy 0.1.0

An async Rust client library for the Hevy public API (https://api.hevyapp.com/docs/)
Documentation

hevy

An async Rust client library for the Hevy API — the public REST API for the Hevy workout tracking app.

Hevy's public API is only available to Hevy Pro users. Grab an API key from your developer settings before using this crate.

Per Hevy's own docs: "we make no guarantees that we won't completely change the structure or abandon the project entirely, so use it at your own risk." This crate follows the documented 0.0.1 OpenAPI spec as closely as possible and deserializes leniently where the docs are inconsistent.

Features

  • Full coverage of the documented API surface:
    • Workouts — list, get, create, update, count, and sync via events
    • Routines — list, get, create, update
    • Routine folders — list, get, create
    • Exercise templates — list, get, create custom exercises
    • Exercise history — fetch historical sets for an exercise, with optional date filtering
    • Body measurements — list, get, create, update
    • User info — fetch the authenticated user's profile
  • Fully async, built on reqwest + tokio
  • Typed request/response models with serde
  • Ergonomic builders for constructing workouts and routines
  • Structured error type ([HevyError]) distinguishing transport errors, decode errors, and API errors (with status code + message)

Installation

cargo add hevy

Or add it to your Cargo.toml manually:

[dependencies]
hevy = "0.1"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }

Usage

use hevy::{CreateWorkoutRequest, HevyClient, NewWorkout, WorkoutExerciseInput, WorkoutSetInput};

#[tokio::main]
async fn main() -> hevy::Result<()> {
    let client = HevyClient::new("YOUR_API_KEY");

    // List workouts.
    let page = client.list_workouts(Some(1), Some(5)).await?;
    for workout in &page.workouts {
        println!("{}: {}", workout.id, workout.title);
    }

    // Log a new workout.
    let workout = NewWorkout::new(
        "Friday Leg Day",
        "2024-08-14T12:00:00Z",
        "2024-08-14T12:30:00Z",
    )
    .with_exercise(
        WorkoutExerciseInput::new("D04AC939").with_set(WorkoutSetInput::normal(100.0, 10)),
    );
    let created = client.create_workout(&CreateWorkoutRequest::new(workout)).await?;
    println!("Created workout {}", created.id);

    Ok(())
}

See examples/basic_usage.rs for a more complete tour (fetching your profile, listing workouts, and logging a new one). Run it with:

HEVY_API_KEY=your-key cargo run --example basic_usage

Error handling

Every fallible method returns [hevy::Result<T>], where errors are represented by [hevy::HevyError]:

  • HevyError::Request — the HTTP request itself failed (network, TLS, timeout, etc.)
  • HevyError::Decode — the response body couldn't be parsed into the expected type
  • HevyError::Api { status, message } — the API responded with a non-2xx status; message is extracted from the response's error field when present
  • HevyError::Config — the client was misconfigured

Testing

The test suite uses wiremock to mock the Hevy API over HTTP, so no real API key or network access is required:

cargo test

License

MIT