A Rust client for EDC.
Install from crates.io
[dependencies]
edc-connector-client = "0.1"Fetching an asset with id 1 and reading the description property as string.
use edc_connector_client::{Auth, EdcConnectorClient};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = EdcConnectorClient::builder()
.management_url("http://myedc")
.with_auth(Auth::api_token("password"))
.build()?;
let asset = client.assets().get("1").await?;
println!("Got {:?}", asset);
println!(
"Property description: {:?}",
asset.property::<String>("description").unwrap()
);
Ok(())
}The client supports these mechanisms via Auth:
Auth::api_token("...")sends the token in theX-Api-Keyheader.Auth::bearer_token("...")sends a fixedAuthorization: Bearertoken.Auth::oauth(OAuth2Config)obtains a token with the OAuth2 client credentials grant and refreshes it when it expires.Auth::token_exchange(TokenExchangeConfig)exchanges a workload credential (e.g. a projected Kubernetes ServiceAccount token) at an RFC 8693 token exchange broker for a short-lived scoped token, as described in the JAD token exchange spec. The exchanged token is cached until it expires and the credential file is re-read on every exchange, so rotation is picked up. No client credentials are sent: the subject token is the sole proof of identity.
use edc_connector_client::{Auth, EdcConnectorClient, SubjectToken, TokenExchangeConfig};
let auth = Auth::token_exchange(
TokenExchangeConfig::builder()
.token_exchange_url("http://jwtlet.edc-v.svc.cluster.local:8080/token")
.subject_token(SubjectToken::file("/var/run/secrets/jwtlet/token"))
.resource("<participant-context-id>") // becomes the `sub` claim
.audience("edcv") // default
.scopes(vec!["management-api:assets:read".to_string()])
.build(),
)?;
let client = EdcConnectorClient::builder()
.management_url("http://myedc")
.with_auth(auth)
.participant_context("<participant-context-id>")
.build()?;dataplaneMetadata replaces the deprecated dataAddress on assets (EDC 0.18+). Labels and
profiles are used to select a data plane, while properties are handed over to it.
use edc_connector_client::types::asset::{DataplaneMetadata, NewAsset};
let asset = NewAsset::builder()
.id("1")
.property("description", "An asset")
.dataplane_metadata(
DataplaneMetadata::builder()
.label("http")
.profile("http-profile")
.property("baseUrl", "https://example.com/data")
.build(),
)
.build();
let response = client.assets().create(&asset).await?;Calls go through client.<api>(EdcConnectorApiVersion::V5). Participant scoped
resources (assets, policies, contract definitions, negotiations, agreements,
transfers, catalog, data planes, discovery) are routed under
/v5/participants/{participant_context}/... when the client is built with
.participant_context(..). Global resources ignore the participant context and
need a token with the management-api:admin scope (profiles can be read with
management-api:profiles:read):
| Accessor | Resource |
|---|---|
participants(V5) |
/participants (create, get, list, update, delete, profiles) |
participant_configs(V5) |
/participants/{id}/config (get, save, patch) |
dataspace_profiles(V5) |
/dataspaceprofiles |
common_expression_language(V5) |
/celexpressions (incl. test) |
dcp_scopes(V5) |
/dcpscopes |
cached_documents(V5) |
/cacheddocuments (incl. refresh) |
schema_validators(V5) |
/schemavalidators |
use edc_connector_client::{types::participants::ParticipantContextConfigPatch, EdcConnectorApiVersion};
let participants = client.participants(EdcConnectorApiVersion::V5).list(0, 50).await?;
client
.participant_configs(EdcConnectorApiVersion::V5)
.patch(
"my-participant",
&ParticipantContextConfigPatch::builder()
.entry("edc.participant.id", "my-participant")
.remove_entry("obsolete.key")
.build(),
)
.await?;git clone https://github.com/dataspace-rs/edc-rs.git
cd edc-rs
cargo build
Some tests run against a running instance of EDC.
You can use docker compose to start an instance for testing.
docker compose -f testing/docker-compose.yml up -d
cargo test
The tests setup was mostly derived by the Typescript client edc-connector-client