spacetraders-client 0.1.0

Async Rust client for the SpaceTraders API v2 with priority-aware rate limiting and retry
Documentation

spacetraders-client

crates.io docs.rs license

Async Rust client for the SpaceTraders API v2.

The crate is built around generated types and request methods from the official OpenAPI document, with a smaller hand-written layer on top for the parts a bot usually cares about: rate limiting, retries, priorities, and a friendlier StClient API for common endpoints.

[dependencies]
spacetraders-client = "0.1"

Quick start

use spacetraders_client::{RequestScheduler, StClient};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = StClient::new(
        "https://api.spacetraders.io/v2",
        std::env::var("AGENT_TOKEN")?,
        RequestScheduler::new(2),
    );

    let status = client.status().await?;
    println!("server: {}", status.description);

    let agent = client.my_agent().await?;
    println!("agent {} has {} credits", agent.data.symbol, agent.data.credits);

    Ok(())
}

There is also a runnable example which can register a new agent and then call a couple of basic endpoints:

AGENT_TOKEN=... cargo run --example register_and_status

What is wrapped today?

StClient currently has convenience methods for:

  • status, error codes, agents, factions, and account data
  • contracts: list, inspect, accept, deliver, fulfill
  • fleet basics: list ships, inspect ships, nav, dock/orbit, jump/warp, refuel
  • cargo and trade actions: buy, sell, jettison, transfer, negotiate
  • mining and surveying: extract, siphon, survey, chart, refine
  • fitting and maintenance: mounts, modules, scans, repair, scrap
  • systems and waypoints: markets, shipyards, jump gates, construction, supply chain

Each convenience method has a matching _with_priority variant. For example, get_my_ships(...) uses normal priority, while get_my_ships_with_priority(..., RequestPriority::Critical) can jump ahead of background work. Low-priority requests still age upward over time, so they do not sit in the queue forever.

The generated types module is re-exported as spacetraders_client::types.

Request behavior

SpaceTraders has tight rate limits, so the client puts every convenience request through a shared scheduler before it hits the API.

  • RequestScheduler::new(2) is the normal SpaceTraders setup: 2 sustained requests per second, with a burst bucket of 10.
  • Priorities are Low, Normal, and Critical.
  • Retry-After is honored when the server sends it. Otherwise the client falls back to exponential backoff with jitter.
  • GET requests may be retried after transient failures.
  • Mutating requests are more careful: a 429 can be retried because the server rejected it before doing the action, but an ambiguous 5xx is not replayed.

That last bit matters. Accidentally sending the same sell, transfer, jump, or contract action twice can make a bot very confused.

Regenerating generated code

The generated sources are checked in, so a normal build does not need the OpenAPI spec or the code-generation stack.

To update the generated client after a SpaceTraders API release:

curl -sSL \
  https://raw.githubusercontent.com/SpaceTradersAPI/api-docs/main/reference/SpaceTraders.json \
  -o spec.json

cargo run --example regenerate
cargo test

This rewrites:

  • src/generated/codegen.rs
  • src/generated/display_impls.rs

Please do not hand-edit those files unless you are deliberately testing a local codegen change. The next regeneration will replace them.

A note about the spec

The SpaceTraders OpenAPI document is used as a local input only. It is not checked in and is not included in the published crate, because the upstream spec is licensed as "No Permission".

The crate does publish the generated Rust source under this project's MIT license. In other words: the spec stays local, the generated Rust is part of the crate.

The regeneration example also does a little cleanup before calling progenitor: it strips OpenAPI 3.1-style null unions and vendor extensions, keeps the JSON request/response shapes this crate needs, and deduplicates some inline schemas so typify reuses the named component types.

Display impls

typify turns constrained strings into newtypes such as AgentSymbol, SystemSymbol, and WaypointSymbol. The regenerate example scans the generated AST and writes Display impls for those string newtypes into src/generated/display_impls.rs.

MSRV

Rust 1.88, Edition 2024.

Observability notes

  • The client emits tracing spans for requests.
  • request_activity_snapshot() reads process-global counters, not per-client counters.
  • StClient::set_token replaces the bearer token, but it does not zeroize the previous string.

License

MIT. See LICENSE.