Expand description
bee-rs — Rust client for the Swarm Bee API.
Functional parity target with bee-js (the canonical TypeScript client) and bee-go (the typed Go port). bee-go is the primary reference for shape and behavior; bee-js is the source of truth for wire-format edge cases.
§Quick start
Connect to a local Bee node, buy a postage batch, upload a few bytes, and download them back:
use std::time::Duration;
use bee::{Client, storage::StorageOptions};
use bee::swarm::Size;
use bytes::Bytes;
let client = Client::new("http://localhost:1633")?;
// Health check the node before we do anything else.
let health = client.debug().health().await?;
assert_eq!(health.status, "ok");
// Buy 1 GB of storage for 30 days at the current chain price.
let size = Size::from_gigabytes(1.0)?;
let duration = Duration::from_secs(30 * 24 * 60 * 60);
let batch_id = bee::storage::buy_storage(
&client, size, duration, &StorageOptions::default(),
).await?;
// Upload + download round-trip.
let result = client
.file()
.upload_data(&batch_id, Bytes::from_static(b"Hello Swarm!"), None)
.await?;
let body = client.file().download_data(&result.reference, None).await?;
assert_eq!(&body[..], b"Hello Swarm!");§Module map
bee-rs is a sub-service client: the top-level Client yields one
handle per Bee API domain. Sub-services are cheap to construct
(Arc<Inner> + accessor) so it is fine to call them on every
request.
api— generic/api/*endpoints (pin, tag, stewardship, grantee, envelope) plus the upload / download option structs and rich return types.file— bytes, files, chunks, SOC, feeds, and tar-packed collections; offlinehash_directory/hash_collection_entries; chunk-by-chunkstream_directorywith progress callback.postage— postage batch CRUD plus pure stamp math (get_stamp_cost,get_amount_for_duration,get_depth_for_size, …) and an offlineStamper.debug— operator endpoints: health, versions, peers, accounting, chequebook, stake, transactions.pss— Postal Service: send + websocket subscribe / receive.gsoc— Generic Single-Owner Chunk send / subscribe.manifest— Mantaray trie,ResourceLocator, offlineresolve_path.swarm— typed bytes, BMT chunk addressing, SOC primitives, token math,BeeDuration,Size, and the crate-levelErrorenum.storage— high-level(size, duration)helpers built on top ofClientandpostage.dev—DevClientwrapper for talking tobee dev.
§Bee version compatibility
This client targets Bee 2.7.2-rc1 / API 8.0.0 (the values pinned
in debug::SUPPORTED_BEE_VERSION_EXACT and
debug::SUPPORTED_API_VERSION). At startup, prefer
debug::DebugApi::is_supported_api_version for a major-compatible
check or debug::DebugApi::is_supported_exact_version for a
strict pin. Older or newer Bee instances usually work — unknown
response fields are ignored — but new endpoints will return 404 and
breaking wire-format changes will surface as Error::Json.
§Authentication, timeouts, and proxies
Client::new constructs a default reqwest::Client with no
auth, no request timeout, and no custom TLS roots. For anything
beyond a trusted local node, build a reqwest::Client with the
settings you need and pass it via Client::with_http_client:
use std::time::Duration;
use reqwest::header::{AUTHORIZATION, HeaderMap, HeaderValue};
let mut headers = HeaderMap::new();
headers.insert(AUTHORIZATION, HeaderValue::from_static("Bearer …"));
let http = reqwest::Client::builder()
.timeout(Duration::from_secs(30))
.default_headers(headers)
.build()
.map_err(bee::Error::Transport)?;
let client = bee::Client::with_http_client("https://bee.example.com", http)?;Bee gates /stamps, /chequebook, /stake, /transactions, and
the operator endpoints behind tokens in production. Proxies are
honored from the HTTP_PROXY / HTTPS_PROXY env vars unless you
call .no_proxy() on the builder.
No automatic retries are performed. Use a layered HTTP client (e.g.
reqwest-middleware + reqwest-retry) if you need them.
§Concurrency
Client is Send + Sync + Clone. Cloning is Arc-cheap
(Arc<Inner> under the hood), so pass a clone into spawned tasks
rather than wrapping in Arc<Mutex<…>>. Sub-service handles
(file::FileApi, postage::PostageApi, …) are likewise cheap
and share the same underlying HTTP client + connection pool.
§Cancellation
Dropping the future returned by any endpoint cancels the in-flight
HTTP request. For uploads, chunks already accepted by the local
Bee node may remain in the local reserve but the upload is not
committed (no manifest reference is returned).
file::FileApi::stream_directory and
file::FileApi::stream_collection_entries upload chunk-by-chunk
and can leave orphan chunks if cancelled mid-stream.
§Streaming vs. buffered transfers
file::FileApi::download_data / file::FileApi::download_file
buffer the full body into bytes::Bytes before returning — fine
for ≤ a few hundred MB, but will OOM on multi-GB references. For
larger downloads, use file::FileApi::download_data_response (or
download_file_response) which returns the raw reqwest::Response
so you can drive reqwest::Response::bytes_stream yourself.
Uploads accept impl Into<Bytes> and stream the body to Bee. The
chunk-by-chunk variants (file::FileApi::stream_directory and
stream_collection_entries) bound peak memory at the BMT chunk
size regardless of file size and report progress via a
caller-supplied file::OnStreamProgressFn.
§Errors
Every fallible call returns Result<T, Error>. Error
is a single enum so callers can match on the variant of interest:
match client.debug().health().await {
Ok(h) if h.status == "ok" => println!("ready: bee {}", h.version),
Ok(h) => println!("not healthy: status={}", h.status),
Err(bee::Error::Response { status, .. }) => println!("bee returned {status}"),
Err(e) => return Err(e),
}As a rule of thumb: 5xx responses and Error::Transport errors
(DNS, connection refused, EOF) are retry candidates with backoff;
4xx Error::Response errors (invalid batch ID, depth out of
range, immutable-flag mismatch) are caller bugs and re-issuing the
same request will fail the same way. POST /bytes is idempotent
for the same (data, batch_id) tuple — Bee returns the same
content reference.
§Observability
bee-rs depends on tracing but does not currently emit spans or
events. Wrap reqwest::Client with reqwest-tracing (or your
own middleware) before passing it to Client::with_http_client
to get request-level spans. Bee’s own
debug::DebugApi::set_logger_verbosity controls server-side
verbosity at runtime.
§Cargo features
default = [] — there are no opt-in features today. The crate
always builds with reqwest’s rustls-tls backend; native-TLS
(OS trust store) is not currently exposed. Open an issue if you
need it for a corporate-CA deployment.
§MSRV
Minimum supported Rust version is 1.85 (Rust 2024 edition).
See Cargo.toml rust-version.
§Testing
Point Client::new at a wiremock mock server (a dev-dep of
this crate, used in our own tests) to test code that calls bee-rs
without a real Bee:
let server = MockServer::start().await;
Mock::given(method("GET"))
.respond_with(ResponseTemplate::new(200)
.set_body_string(r#"{"status":"ok","version":"2.7.2","apiVersion":"8.0.0"}"#))
.mount(&server)
.await;
let client = bee::Client::new(&server.uri())?;
let h = client.debug().health().await?;
assert_eq!(h.status, "ok");§Common pitfalls
- A freshly-purchased postage batch is not usable for ~2-3 minutes
on Sepolia (block time × N confirmations). Poll
postage::PostageBatch::usablebefore uploading or you will get HTTP 422 “stamp not usable”. - Dilute is one-way: depth can only grow, never shrink.
swarm::Referencevalues are 32 bytes (plain) or 64 bytes (encrypted). Passing an encrypted reference to a plain download silently returns garbage — match the reference type to how the data was uploaded.- Feed updates require the same
(topic, signer)pair every time; a new signer creates a new feed, not an update. - On a
bee devnode, all chain / chequebook / stake endpoints return 404 — seeDevClient.
Re-exports§
Modules§
- api
- Generic API surface: upload/download options, headers, rich
return types, and the pin / tag / stewardship endpoint methods.
Mirrors
pkg/apiin bee-go. - debug
- Debug / operator endpoints. Mirrors
pkg/debugin bee-go. - dev
- Bee dev-mode wrapper. The dev-mode endpoint surface is a strict
subset of production Bee, so this is mostly a documentation /
discovery signal: callers can
let bee = DevClient::new(url)?;and use the same accessors they already know fromClient. - file
- File / data / chunk / SOC / feed / collection uploads and
downloads. Mirrors
pkg/filein bee-go. - gsoc
- GSOC send / subscribe + offline
soc_address. Mirrorspkg/gsocin bee-go and bee-jsBee.gsocSend/gsocSubscribe. - manifest
- Mantaray manifest trie. Mirrors
pkg/manifestin bee-go andsrc/manifestin bee-js. - postage
- Postage batch CRUD + stamp metadata. Mirrors
pkg/postagein bee-go. - pss
- PSS send / subscribe / receive. Mirrors
pkg/pssin bee-go andBee.pssSend/Bee.pssSubscribe/Bee.pssReceivein bee-js. - storage
- High-level storage helpers built on top of
Client. - swarm
- Foundational types for the Swarm protocol: typed bytes, BMT chunk addressing, SOC primitives, and the crate-level error type.
Structs§
- Client
- Top-level Bee API client.
Constants§
- MAX_
JSON_ RESPONSE_ BYTES - Maximum size of a structured JSON / NDJSON response body that the
crate will buffer. Bee responses larger than this are rejected
before the body is fully read; bulk file downloads should bypass
the in-memory pipeline via
crate::file::FileApi::download_file_response.