strava-wrapper 0.1.1

A Rust wrapper for the Strava API
Documentation

Strava API Wrapper

An asynchronous wrapper for the Strava API, written in Rust.

Builder-style, trait-driven, and covers the full public v3 surface: activities, athletes, clubs, gear, routes, segments, segment efforts, streams, and uploads, plus the OAuth token and deauthorize flows.


Installation

[dependencies]
strava-wrapper = "0.1.0"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }

Quick start

use strava_wrapper::api::StravaAPI;
use strava_wrapper::prelude::*;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = StravaAPI::new("https://www.strava.com/api", "YOUR_ACCESS_TOKEN");

    // Read the authenticated athlete.
    let me = api.athlete().get().send().await?;

    // Fetch an activity by id.
    let activity = api.activities().get().id(123).send().await?;

    // Paginate.
    let comments = api
        .activities()
        .comments()
        .id(123)
        .per_page(10)
        .page(2)
        .send()
        .await?;

    Ok(())
}

OAuth

use strava_wrapper::auth::{get_token, refresh_token, deauthorize};

// 1. Exchange authorization code for an access token.
let token = get_token(client_id, &client_secret, &auth_code).await?;

// 2. Later, swap a soon-to-expire access token for a new one.
let refreshed = refresh_token(client_id, &client_secret, &token.refresh_token).await?;
api.set_token(refreshed.access_token);

// 3. Revoke access on logout.
deauthorize(&api.token()).await?;

Writes

use strava_wrapper::models::{CreateActivity, UpdatableActivity};

// Create a manual activity.
api.activities().create(CreateActivity {
    name: "Commute".into(),
    sport_type: "Ride".into(),
    start_date_local: "2024-06-01T08:00:00".into(),
    elapsed_time: 1800,
    activity_type: None,
    description: None,
    distance: None,
    trainer: None,
    commute: Some(1),
}).send().await?;

// Update fields on an existing activity.
api.activities().update(456, UpdatableActivity {
    name: Some("Evening Ride".into()),
    commute: Some(true),
    ..Default::default()
}).send().await?;

// Star a segment.
api.segments().star(789, true).send().await?;

// Update weight.
api.athlete().update(70.5).send().await?;

Streams

use strava_wrapper::filters::streams::StreamKey;

let streams = api
    .streams()
    .activity()
    .id(123)
    .keys(&[StreamKey::Time, StreamKey::Heartrate, StreamKey::Watts])
    .send()
    .await?;

Uploads

use strava_wrapper::filters::uploads::UploadDataType;

let bytes = std::fs::read("ride.fit")?;
let upload = api
    .uploads()
    .upload(bytes, UploadDataType::Fit)
    .name("Morning Ride")
    .send()
    .await?;

// Poll processing status.
let status = api.uploads().get().id(upload.id.unwrap()).send().await?;

Errors

All network calls return Result<T, ErrorWrapper>. ErrorWrapper is an enum with Network, Parse, Api, and Url variants and implements Display + std::error::Error, so it composes with ? in your own error types.


Testing

cargo test --all