Skip to main content

JsonClient

Struct JsonClient 

Source
pub struct JsonClient { /* private fields */ }
Expand description

A client for the Canton JSON Ledger API over HTTP.

Implementations§

Source§

impl JsonClient

Source

pub fn new(base_url: impl Into<String>) -> Self

Create a JSON client for base_url (e.g. http://localhost:3975), with no authentication. A trailing slash on base_url is tolerated.

Source

pub fn from_env() -> Result<Self>

Build a client from a local development network exported into the environment — the JSON counterpart to Config::from_env.

eval "$(canton-devkit localnet env demo)"

reads CANTON_JSON_LEDGER_API_URL and the default participant’s JWT. See canton_core::localnet for the full contract.

§Errors

Returns Error::InvalidRequest when no JSON endpoint is exported, naming the variable and the command that produces it. A missing token is not an error: an unauthenticated LocalNet is a normal target.

Source

pub fn from_env_for(role: &str) -> Result<Self>

The same, for a participant other than the default: "app-user", "sv", or any role the exporter knows.

§Errors

As Self::from_env, naming that role’s variable.

Source

pub fn with_timeout(self, timeout: Duration) -> Self

How long one HTTP attempt may take (default 30s), the JSON lane’s counterpart to Config::with_timeout.

reqwest imposes no timeout of its own, so without this a request to a participant that accepts the connection and then goes quiet never returns. Applied per attempt: under Self::with_retry each try gets the full budget, matching how the gRPC channel’s timeout composes with its retries.

The clock covers the whole exchange — connecting, sending, and reading the response body — so it is a real bound rather than a bound on the first byte.

Source

pub fn with_max_decoding_message_size(self, bytes: usize) -> Self

The largest WebSocket message this client will accept, in bytes — the JSON lane’s counterpart to Config::with_max_decoding_message_size, and the same default.

A WS stream carries the same payloads the gRPC one does, so it needs the same ceiling. Left alone, tungstenite applies its own: 64 MiB per message and 16 MiB per frame, the second of which is the one a large update meets first. Both are set from this value, so a frame is capped only by what the caller asked for.

Does not affect the HTTP (POST) lane, which has no ceiling to raise.

Source

pub fn with_retry(self, retry: RetryConfig) -> Self

Retry requests on retriable errors (category-first classification of the participant’s error body, transient HTTP statuses, connection failures) with exponential backoff, honouring a server-recommended retry delay — the same policy as the gRPC client’s unary retries. Off by default. Safe for command submission too: the command id in the body stays fixed across attempts, so the participant de-duplicates. Streaming (the WS lane) resumes via its own reconnect policy instead.

Source

pub fn with_tls(self, tls: &TlsConfig) -> Result<Self>

Use TLS for the HTTP connection: a custom CA (server-side TLS against a private/self-signed server) and/or a client identity (mutual TLS). This is a terminal builder step — call it last, after Self::with_token / Self::with_oidc.

An http:// base URL is normalised to https:// so TLS is never silently downgraded: reqwest selects TLS from the URL scheme (not from the configured certificates), and the WebSocket lane maps http→ws / https→wss the same way, so an http:// base URL with with_tls would otherwise send plaintext HTTP and open a ws:// socket with the certificates unused. Detection is case-insensitive, mirroring the gRPC channel builder (canton-core’s resolve_endpoint).

TlsConfig::domain_name is not applied here: reqwest derives SNI from the request URL (it is a gRPC/tonic knob).

§Errors

Returns Error::InvalidRequest if a certificate/identity PEM is invalid or the HTTPS client cannot be built.

Source

pub fn with_token(self, token: impl Into<String>) -> Self

Authenticate with a fixed bearer token.

Source

pub fn with_oidc(self, provider: TokenProvider) -> Self

Authenticate with an OIDC token provider (client-credentials, auto-refresh).

Source

pub async fn version(&self) -> Result<String>

The participant’s Ledger API version (GET /v2/version, unauthenticated).

§Errors

Returns an Error if the request fails or the response is malformed.

Source

pub async fn ledger_end(&self) -> Result<i64>

The current ledger end offset (GET /v2/state/ledger-end, authenticated).

§Errors

Returns an Error if authentication or the request fails.

Source

pub async fn list_packages(&self) -> Result<Vec<String>>

The ids of every package the participant knows (GET /v2/packages).

The JSON twin of canton-admin’s AdminClient::list_packages, for a deployment that exposes only the JSON Ledger API. What a package is to the ledger — uploaded, vetted, both — is answered by package_status, not by presence in this list.

§Errors

Returns an Error if authentication or the request fails.

Source

pub async fn package_status(&self, package_id: &str) -> Result<PackageStatus>

Whether the participant has a package registered (GET /v2/packages/{package-id}/status).

Answers with the same PackageStatus the gRPC path returns, so a caller can switch transports without re-learning the vocabulary. A status this build does not know is an Error::UnexpectedResponse rather than a silent PACKAGE_STATUS_UNSPECIFIED: the participant said something definite, and guessing would hide it.

§Errors

Returns Error::InvalidRequest if package_id is empty or could not form a path segment, and an Error if authentication or the request fails or the status is not one this build knows.

Source

pub async fn participant_id(&self) -> Result<String>

The participant’s own identifier (GET /v2/parties/participant-id).

§Errors

Returns an Error if authentication or the request fails.

Source

pub async fn list_known_parties_page( &self, page_size: i32, page_token: Option<String>, ) -> Result<(Vec<PartyDetails>, Option<String>)>

One page of the parties the participant knows (GET /v2/parties). Pass the returned token to fetch the next page; page_size 0 uses the server default.

Answers with the same PartyDetails the gRPC path returns. Requires ParticipantAdmin or an identity-provider admin, as the gRPC call does; a plain user is refused.

§Errors

Returns an Error if authentication or the request fails.

Source

pub async fn list_known_parties(&self) -> Result<Vec<PartyDetails>>

Every party the participant knows, following pagination internally (GET /v2/parties).

§Errors

Returns an Error if authentication or any page request fails, and Error::UnexpectedResponse if the participant repeats a page token — the list would be a prefix that looks complete, so it fails instead.

Source

pub async fn get_parties( &self, parties: Vec<String>, ) -> Result<Vec<PartyDetails>>

Details for specific parties (GET /v2/parties/{party}, the rest as ?parties=). Unknown parties are omitted from the result rather than erroring, as over gRPC. A plain user may only ask about parties it can act or read as; anything else is refused by the participant.

§Errors

Returns Error::InvalidRequest if parties is empty or one of them cannot form a path segment, and an Error if authentication or the request fails.

Source

pub async fn allocate_party( &self, party_id_hint: Option<&str>, ) -> Result<PartyDetails>

Allocate a party (POST /v2/parties). party_id_hint suggests the local part of the id; the participant returns the actual PartyDetails (party = "<hint>::<fingerprint>").

The same call as canton-admin’s allocate_party, over JSON. For the rest of the request — synchronizer, user, annotations — see allocate_party_with.

Requires the ParticipantAdmin right. Not retried: allocation is a non-idempotent topology mutation, so a transient failure surfaces to the caller rather than risking two parties.

§Errors

Returns an Error if authentication or authorization fails, or the request fails.

Source

pub async fn allocate_party_with( &self, request: &AllocateParty, ) -> Result<PartyDetails>

Allocate a party with the full request (POST /v2/parties).

§Errors

As allocate_party.

Source

pub async fn update_party_details( &self, details: &PartyDetails, update_paths: &[&str], ) -> Result<PartyDetails>

Update the participant-local details of a party (PATCH /v2/parties/{party}).

update_paths is the field mask — which of details to apply, in the gRPC message’s spelling: local_metadata.annotations, or local_metadata for all of it. To remove an annotation, send its key with an empty value. Carrying resource_version from a read makes the update conditional on nobody having changed the party since: a stale version is refused with a 409 (CONCURRENT_PARTY_DETAILS_UPDATE_DETECTED) the participant classifies as contention, so Error::is_retriable is true and the right move is to read again and update again.

Not retried, for the reason allocate_party gives: a lost response is resolved by reading the party back.

§Errors

Returns Error::InvalidRequest if update_paths is empty — the participant refuses an empty mask, and this says so before the trip — or the party cannot form a path segment; an Error if authentication or authorization fails, the request fails, or the participant reports a concurrent change.

Source

pub async fn submit_and_wait_for_transaction( &self, commands: &JsonCommands, ) -> Result<JsonSubmitResponse>

Submit commands and wait for the resulting transaction (POST /v2/commands/submit-and-wait-for-transaction).

§Errors

Returns an Error if authentication fails, the command is rejected (surfaced as Error::Http carrying the participant’s error body), or the response is malformed.

Source

pub async fn submit(&self, commands: &JsonCommands) -> Result<()>

Submit without waiting (POST /v2/commands/async/submit): the participant accepts the command and the outcome arrives on the completion stream.

The gRPC lane has had this since M1. Note what a failure here means: the command may still have committed, so reach for Self::submission rather than this method when losing the outcome is not acceptable.

§Errors

Returns an Error if authentication fails or the participant rejects the submission (Error::Http with its error body).

Source

pub async fn submit_and_wait( &self, commands: &JsonCommands, ) -> Result<JsonSubmitAndWaitResponse>

Submit and wait for the completion (POST /v2/commands/submit-and-wait) without fetching the transaction — the update id and completion offset.

§Errors

Returns an Error if authentication fails or the command is rejected.

Source

pub async fn events_by_contract_id( &self, contract_id: impl Into<String>, parties: Vec<String>, ) -> Result<Value>

The create and consuming-exercise events of one contract (POST /v2/events/events-by-contract-id), as seen by parties.

Returns the raw response object; a contract that has been pruned or is invisible to parties comes back as a CONTRACT_EVENTS_NOT_FOUND error rather than an empty result.

§Errors

Returns an Error if authentication or the request fails, or the contract has no events visible to parties.

Source

pub async fn latest_pruned_offsets(&self) -> Result<PrunedOffsets>

How far the participant has pruned (GET /v2/state/latest-pruned-offsets), the JSON twin of CantonClient::latest_pruned_offsets.

§Errors

Returns an Error if authentication or the request fails.

Source

pub async fn update_by_offset( &self, offset: i64, parties: Vec<String>, ) -> Result<Option<Value>>

The update at offset, as parties see it (POST /v2/updates/update-by-offset), in the default format of UpdatesRequest::new: the JSON twin of CantonClient::update_by_offset. The element is raw JSON ({"update": …}), as Self::updates returns them. Ok(None) when no update at that offset is visible to parties.

§Errors

Returns an Error if authentication or the request fails.

Source

pub async fn update_by_offset_with( &self, offset: i64, format: &UpdatesRequest, ) -> Result<Option<Value>>

Like Self::update_by_offset, in the format an UpdatesRequest describes. Its offsets are not used.

§Errors

Returns an Error if the request names no party, or authentication or the request fails.

Source

pub async fn update_by_id( &self, update_id: impl Into<String>, parties: Vec<String>, ) -> Result<Option<Value>>

The update with id update_id, as parties see it (POST /v2/updates/update-by-id): the JSON twin of CantonClient::update_by_id. Ok(None) when no update with that id is visible to parties.

§Errors

Returns an Error if authentication or the request fails.

Source

pub async fn update_by_id_with( &self, update_id: impl Into<String>, format: &UpdatesRequest, ) -> Result<Option<Value>>

Like Self::update_by_id, in the format an UpdatesRequest describes. Its offsets are not used.

§Errors

Returns an Error if the request names no party, or authentication or the request fails.

Source

pub fn submission(&self, commands: JsonCommands) -> JsonSubmission

Fix a submission’s identity before sending it, returning a JsonSubmission that carries its ChangeId — the JSON lane’s CantonClient::submission.

Source

pub async fn active_contracts( &self, parties: Vec<String>, active_at_offset: i64, limit: Option<i64>, ) -> Result<Vec<Value>>

The active contract set snapshot at active_at_offset, wildcard-filtered to parties (POST /v2/state/active-contracts).

This is a bounded read: the node caps results at http-list-max-elements-limit and returns Error::Http 413 past it, so pass a limit for large sets (or use the streaming transport). Each element is raw JSON ({"workflowId": …, "contractEntry": …}).

§Errors

Returns an Error if authentication or the request fails, or the result set exceeds the node limit (413).

Source

pub async fn active_contracts_with( &self, request: &ActiveContractsRequest, limit: Option<i64>, ) -> Result<Vec<Value>>

Like Self::active_contracts, with the full request surface of an ActiveContractsRequest (template/interface filters, created-event blobs, non-verbose records) — the same builder the gRPC lane takes.

§Errors

Returns an Error if authentication or the request fails, or the result set exceeds the node limit (413).

Source

pub async fn updates( &self, parties: Vec<String>, begin_exclusive: i64, end_inclusive: Option<i64>, limit: Option<i64>, ) -> Result<Vec<Value>>

Updates (transactions/reassignments) for parties in the offset range (begin_exclusive, end_inclusive] (POST /v2/updates).

A bounded read like Self::active_contracts: bound it with end_inclusive and/or limit, or the node returns Error::Http 413. Each element is raw JSON ({"update": …}), including OffsetCheckpoint heartbeats.

§Errors

Returns an Error if authentication or the request fails, or the result set exceeds the node limit (413).

Source

pub async fn updates_with( &self, request: &UpdatesRequest, limit: Option<i64>, ) -> Result<Vec<Value>>

Like Self::updates, with the full request surface of an UpdatesRequest (bounds, template/ interface filters, transaction shape, created-event blobs, topology events, non-verbose records) — the same builder the gRPC lane takes.

§Errors

Returns an Error if authentication or the request fails, or the result set exceeds the node limit (413).

Source

pub async fn updates_typed_with( &self, request: &UpdatesRequest, limit: Option<i64>, ) -> Result<Vec<Update>>

Like Self::updates_with, as the SDK’s own Update: the type CantonClient::updates_typed_with yields too. OffsetCheckpoint heartbeats are dropped, as the gRPC lane drops them.

§Errors

Returns an Error if authentication or the request fails, the result set exceeds the node limit (413), or an element is malformed.

Source§

impl JsonClient

Source

pub async fn ws_updates( &self, parties: Vec<String>, begin_exclusive: i64, end_inclusive: Option<i64>, ) -> Result<impl Stream<Item = Result<Value>> + Send + use<>>

Available on crate feature ws only.

Stream updates over WebSocket (feature ws) for parties, starting after begin_exclusive. With end_inclusive the stream is bounded and closes once the range is exhausted; without it the stream tails live. Each item is a raw JSON update ({"update": …}); OffsetCheckpoint heartbeats are filtered out (as in the gRPC CantonClient::updates).

Unlike Self::updates, this is not capped by the node’s list limit. For automatic reconnection use Self::ws_updates_resumable.

§Errors

Returns an Error if the handshake fails; the stream yields Err on a participant error frame or a transport failure.

Source

pub async fn ws_updates_with( &self, request: &UpdatesRequest, ) -> Result<impl Stream<Item = Result<Value>> + Send + use<>>

Available on crate feature ws only.

Like Self::ws_updates, with the full request surface of an UpdatesRequest — the same builder the gRPC lane takes (bounds, filters, shape, blobs, topology events, non-verbose records).

§Errors

Returns an Error if the handshake fails; the stream yields Err on a participant error frame or a transport failure.

Source

pub async fn ws_active_contracts( &self, parties: Vec<String>, active_at_offset: i64, ) -> Result<impl Stream<Item = Result<Value>> + Send + use<>>

Available on crate feature ws only.

Stream the active contract set snapshot at active_at_offset over WebSocket (feature ws), wildcard-filtered to parties. The stream closes when the snapshot is fully delivered. Each item is raw JSON ({"workflowId": …, "contractEntry": …}).

Unlike Self::active_contracts, this is not capped by the node’s list limit.

§Errors

Returns an Error if the handshake fails; the stream yields Err on a participant error frame or a transport failure.

Source

pub async fn ws_active_contracts_with( &self, request: &ActiveContractsRequest, ) -> Result<impl Stream<Item = Result<Value>> + Send + use<>>

Available on crate feature ws only.

Like Self::ws_active_contracts, with the full request surface of an ActiveContractsRequest — the same builder the gRPC lane takes.

§Errors

Returns an Error if the handshake fails; the stream yields Err on a participant error frame or a transport failure.

Source

pub async fn ws_completions( &self, parties: Vec<String>, begin_exclusive: i64, ) -> Result<impl Stream<Item = Result<Value>> + Send + use<>>

Available on crate feature ws only.

Stream command completions over WebSocket (feature ws) for parties, starting after begin_exclusive. Each item is a raw JSON completion; OffsetCheckpoint heartbeats are filtered out.

§Errors

Returns an Error if the handshake fails; the stream yields Err on a participant error frame or a transport failure.

Source

pub async fn ws_completions_with( &self, request: &CompletionsRequest, ) -> Result<impl Stream<Item = Result<Value>> + Send + use<>>

Available on crate feature ws only.

Like Self::ws_completions, with the full request surface of a CompletionsRequest — including the submitting user_id to scope the stream to (the same builder the gRPC lane takes).

§Errors

Returns an Error if the handshake fails; the stream yields Err on a participant error frame or a transport failure.

Source

pub fn ws_active_contracts_resumable( &self, parties: Vec<String>, active_at_offset: i64, ) -> impl Stream<Item = Result<Value>> + Send + use<>

Available on crate feature ws only.

Like Self::ws_active_contracts, but resumable: on a retriable disconnect it resubscribes from the last continuation token the participant sent, rather than starting the snapshot again.

An ACS snapshot has no offsets to resume from — it is a position in a stream of entries, which is what streamContinuationToken names. The gRPC lane has had a resumable ACS read since M1; this is its counterpart, and without it a WebSocket consumer of a large snapshot had to start over on any blip.

The token is only valid against the same participant, the same active_at_offset and the same filters — all of which are fixed for the life of this stream — and while the snapshot’s offset has not been pruned.

Source

pub fn ws_updates_resumable( &self, parties: Vec<String>, begin_exclusive: i64, ) -> impl Stream<Item = Result<Value>> + Send + use<>

Available on crate feature ws only.

Like Self::ws_updates (unbounded tail), but resumable: on a retriable disconnect it reconnects from the last offset it observed (tracked via OffsetCheckpoint heartbeats and update offsets), with a short backoff and a bounded number of consecutive reconnects. Mirrors the gRPC CantonClient::updates_resumable. Checkpoints are consumed for position tracking and not yielded.

Trait Implementations§

Source§

impl Clone for JsonClient

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for JsonClient

Hand-written for the same reason Config’s is: a base URL can carry credentials in its userinfo (https://user:secret@host), and the derived Debug printed them verbatim — one tracing field holding a client, or one {:?} in a log line, was enough.

The reqwest client is left out entirely — finish_non_exhaustive says so rather than pretending otherwise — because its internals describe a connection pool, not this client.

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<T> FutureExt for T

Source§

fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ

Attaches the provided Context to this type, returning a WithContext wrapper. Read more
Source§

fn with_current_context(self) -> WithContext<Self> ⓘ

Attaches the current Context to this type, returning a WithContext wrapper. Read more
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more