Build a data service¶
This guide explains how to build a data service on top of the dataLOFT management services. A data service exposes datasets to the dataspace through RUN-DSP. RUN-DSP handles all dataspace protocol communication (contract negotiation, transfer lifecycle, authentication) and delegates data operations to your service via gRPC.
The proto definitions are published at codeberg.org/go-dataspace/run-dsrpc. Generate a client and server stub for your language from the .proto files in proto/dsp/v1alpha2/.
Integration levels¶
There are two levels of integration, depending on whether your service acts as a provider only or also drives dataspace operations as a consumer.
Basic integration: implement ProviderService
Your service implements ProviderService from provider.proto. RUN-DSP calls your service when a remote consumer queries the catalogue, negotiates a contract, or initiates a transfer. This is the minimum required to publish datasets into the dataspace.
Full integration: also implement ControlService
Your service calls ControlService from control.proto, which RUN-DSP exposes. This lets your service drive operations from the consumer side: browse remote catalogues, initiate contract negotiations, and manage transfers programmatically. r-squared uses both levels.
Basic integration: ProviderService¶
Implement the ProviderService gRPC server and configure RUN-DSP to call it.
RPCs¶
service ProviderService {
rpc Ping(PingRequest) returns (PingResponse) {}
rpc GetCatalogue(GetCatalogueRequest) returns (GetCatalogueResponse) {}
rpc GetDataset(GetDatasetRequest) returns (GetDatasetResponse) {}
rpc PublishDataset(PublishDatasetRequest) returns (PublishDatasetResponse) {}
rpc ShutdownTransfer(ShutdownTransferRequest) returns (ShutdownTransferResponse) {}
rpc SuspendPublishedDataset(SuspendPublishedDatasetRequest) returns (SuspendPublishedDatasetResponse) {}
rpc UnsuspendPublishedDataset(UnsuspendPublishedDatasetRequest) returns (UnsuspendPublishedDatasetResponse) {}
rpc ReceiveDataset(ReceiveDatasetRequest) returns (ReceiveDatasetResponse) {}
rpc PushDataset(PushDatasetRequest) returns (PushDatasetResponse) {}
}
Ping¶
RUN-DSP calls Ping on startup to verify the provider is reachable and to read its configuration.
Your response must include:
| Field | Description |
|---|---|
provider_name |
Human-readable name for this provider. |
provider_description |
Short description. |
authenticated |
Whether the forwarded authorization header was valid. |
dataservice_id |
A stable UUID for this data service. |
dataservice_url |
The URL from which consumers download data (used in PublishInfo). |
capabilities |
Supported transfer modes: HTTP_PULL, HTTP_PUSH, or both. |
GetCatalogue and GetDataset¶
RUN-DSP calls GetCatalogue when a consumer queries the catalogue. Return a list of Dataset messages representing the datasets your service makes available.
GetDataset is called when a consumer requests a specific dataset by ID. Return the same Dataset structure.
Both calls include a RequesterInfo field that identifies the requester within the dataspace. Use this to apply access control. You can return different datasets to different participants.
The Dataset message carries standard metadata fields (title, description, keywords, media type, byte size, checksum) plus an open metadata map for anything domain-specific.
PublishDataset¶
Called when a contract has been agreed and a pull transfer is about to begin. RUN-DSP passes the dataset ID and a publish_id that is unique to this transfer instance. The same dataset can be published concurrently under multiple publish IDs.
Return a PublishInfo containing:
| Field | Description |
|---|---|
url |
The URL where the consumer can download the data. |
authentication_type |
BEARER or BASIC. |
username / password |
Credentials for the download request. |
For a pull transfer, you generate a short-lived URL (or a pre-signed URL if using S3-compatible storage) and return it here. The consumer then downloads directly from that URL without further involvement from RUN-DSP.
ShutdownTransfer¶
Called when the transfer is complete or terminated. Use the publish_id to clean up any temporary credentials or resources you allocated in PublishDataset.
SuspendPublishedDataset and UnsuspendPublishedDataset¶
Called if the transfer is suspended or resumed mid-flight. Revoke access temporarily on suspend; restore it on unsuspend.
ReceiveDataset¶
Called for push transfers. The consumer wants to send data to your service. Return a PublishInfo containing the URL and credentials where the consumer should upload the data.
PushDataset¶
Called when your service is acting as a provider that pushes data to another provider. Implement this if your service supports HTTP_PUSH capability. Retrieve the upload target from GetProviderDatasetUploadInformation (via ControlService) and perform the upload.
Key types¶
Dataset¶
message Dataset {
string id = 1;
string title = 2;
string access_methods = 3;
repeated Multilingual description = 4;
repeated string keywords = 5;
optional string creator = 6;
optional google.protobuf.Timestamp issued = 7;
optional google.protobuf.Timestamp modified = 8;
map<string, string> metadata = 9;
optional string license = 10;
optional string access_rights = 11;
optional string rights = 12;
int64 byte_size = 13;
string media_type = 14;
optional string format = 15;
optional string compress_format = 16;
optional string package_format = 17;
optional Checksum checksum = 18;
}
Use metadata for any domain-specific fields that do not map to the standard fields. The id must be stable and unique within your service.
PublishInfo¶
message PublishInfo {
string url = 1;
AuthenticationType authentication_type = 2;
string username = 3;
string password = 4;
}
For bearer token auth, put the token in password and leave username empty.
RequesterInfo¶
message RequesterInfo {
string identifier = 1;
string external_id = 2;
AuthenticationStatus authentication_status = 3;
}
identifier is the internal dataspace participant ID. external_id is the DID of the requester. authentication_status tells you whether the request arrived with valid credentials (AUTHENTICATED), no credentials (UNAUTHENTICATED), or from the local RUN-DSP instance (LOCAL_ORIGIN).
Full integration: ControlService¶
ControlService is the interface RUN-DSP exposes to your application. Call it when your service needs to act as a consumer, browsing remote catalogues, negotiating contracts, and managing transfers.
Browsing remote catalogues¶
rpc GetProviderCatalogue(GetProviderCatalogueRequest) returns (GetProviderCatalogueResponse) {}
rpc GetProviderDataset(GetProviderDatasetRequest) returns (GetProviderDatasetResponse) {}
Pass the provider_uri of the remote RUN-DSP instance. RUN-DSP fetches the catalogue on your behalf and returns the list of Dataset messages.
Contract negotiation¶
rpc ContractRequest(ContractRequestRequest) returns (ContractRequestResponse) {}
rpc ContractOffer(ContractOfferRequest) returns (ContractOfferResponse) {}
rpc ContractAccept(ContractAcceptRequest) returns (ContractAcceptResponse) {}
rpc ContractAgree(ContractAgreeRequest) returns (ContractAgreeResponse) {}
rpc ContractVerify(ContractVerifyRequest) returns (ContractVerifyResponse) {}
rpc ContractFinalize(ContractFinalizeRequest) returns (ContractFinalizeResponse) {}
rpc ContractTerminate(ContractTerminateRequest) returns (ContractTerminateResponse) {}
These calls map to IDSA DSP contract negotiation state transitions. For a typical consumer-initiated flow, call ContractRequest with the offer JSON and the provider address. Set auto_accept: true to let RUN-DSP advance the negotiation automatically without waiting for your application to acknowledge each step.
Once the negotiation reaches FINALIZED, use the resulting agreement to request a transfer.
Transfer lifecycle¶
rpc GetProviderDatasetDownloadInformation(...) returns (...) {}
rpc GetProviderDatasetUploadInformation(...) returns (...) {}
rpc InitiatePushTransfer(...) returns (...) {}
rpc SignalTransferComplete(...) returns (...) {}
rpc SignalTransferCancelled(...) returns (...) {}
rpc SignalTransferSuspend(...) returns (...) {}
rpc SignalTransferResume(...) returns (...) {}
For a pull transfer:
- Call
GetProviderDatasetDownloadInformationwith the provider URL and dataset ID. RUN-DSP negotiates the transfer with the remote provider and returns aPublishInfoand atransfer_id. - Download the data from the URL in
PublishInfousing the provided credentials. - Call
SignalTransferCompletewith thetransfer_idto close the transfer on the dataspace side.
For a push transfer, call GetProviderDatasetUploadInformation to get the upload target, perform the upload, then signal completion.
VerifyConnection is a diagnostic call that verifies the connection token between your application and RUN-DSP.
Reference implementations¶
rdsp-s3 is the reference ProviderService implementation. It indexes files from an S3-compatible object store, exposes them as datasets, and generates pre-signed download URLs in PublishDataset. The source is at codeberg.org/go-dataspace/rdsp-s3.
r-squared is the reference data service for the full integration pattern. It pairs with rdsp-s3 as the provider backend and calls ControlService to drive transfers from the consumer side, browsing remote catalogues, initiating contract negotiations, and managing ECG data transfers. The source is at codeberg.org/dataLOFT-platform/r-squared.