edc-rs
EDC-rs
edc-connector-client
A Rust client for EDC.
Installation
Install from crates.io
[dependencies] edc-connector-client = "0.1"
Examples
Basic usage
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(()) }
Authentication
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()?;
Creating an asset with dataplane metadata
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?;
Management API v5 (EDC-V)
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?;
Development
Compiling
git clone https://github.com/dataspace-rs/edc-rs.git cd edc-rs cargo build
Testing
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