Skip to content

Commit

Permalink
docs: example api wrapper usage (#595)
Browse files Browse the repository at this point in the history
  • Loading branch information
richardtreier authored Nov 7, 2023
1 parent f85af62 commit 6037905
Show file tree
Hide file tree
Showing 5 changed files with 255 additions and 12 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ All notable changes to this project will be documented in this file.
#### Patch Changes

- Improved `:extensions:wrapper:wrapper-common-mappers` for broker: `AssetJsonLdUtils`, made some methods public.
- Added example for using the API Wrapper to offer and consume data.

### Deployment Migration Notes

Expand Down
35 changes: 23 additions & 12 deletions docs/getting-started/documentation/api_wrapper.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@ Manging a sovity EDC Connector via the API Wrapper Java Client Library

Introduction to the sovity EDC API Wrapper
========
The sovity EDC API Wrapper contains several APIs, of which some are available in either our sovity EDC CE or our sovity CE EE / Connector-as-a-Servcie (CaaS). These APIs are made accessible via type-safe generated client libraries. Please note that most of these APIs are not yet complete and are under development:
- **Use Case API**: Generic API for Use Case Applications. Its goal is to replace the Management API, so there can be stable endpoints across milestones in the auto-generated client libraries. It's still in development, so expect many new endpoints to be added here in the near future.
- **UI API**: API endpoints for the sovity EDC UI: These endpoints might contain interesting data, that a Use Case Application might profit from, but expect these endpoints to be unstable and subject to change.
- **Enterprise Edition API**: Special API endpoint only available in the Connector-as-a-Service (CaaS). Features such as File Storage are currently in development, but to be expected in the near future.
The sovity EDC API Wrapper contains several APIs, of which some are available in either our sovity EDC CE or our sovity
CE EE / Connector-as-a-Servcie (CaaS). These APIs are made accessible via type-safe generated client libraries. Please
note that most of these APIs are not yet complete and are under development:

- **Use Case API**: Generic API for Use Case Applications. Its goal is to replace the Management API, so there can be
stable endpoints across milestones in the auto-generated client libraries. It's still in development, so expect many
new endpoints to be added here in the near future.
- **UI API**: API endpoints for the sovity EDC UI: These endpoints might contain interesting data, that a Use Case
Application might profit from, but expect these endpoints to be unstable and subject to change.
- **Enterprise Edition API**: Special API endpoint only available in the Connector-as-a-Service (CaaS). Features such as
File Storage are currently in development, but to be expected in the near future.

Using the Java Client Library
========
Expand All @@ -15,20 +22,24 @@ This requires JDK11 or higher, and either a Gradle or Maven project.
Installing The Java Client Library
========
Connect your Maven or Gradle Project to the Github Maven Registry
- Maven: https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-apache-maven-registry#authenticating-to-github-packages
- Gradle: https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-gradle-registry#authenticating-to-github-packages

-
Maven: https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-apache-maven-registry#authenticating-to-github-packages
-
Gradle: https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-gradle-registry#authenticating-to-github-packages
- This might require a Github Personal Access Token (PAT)
Add the Java Client Library to your Maven/Gradle project: https://github.com/sovity/edc-extensions/packages/1825774
Add the Java Client Library to your Maven/Gradle project: https://github.com/sovity/edc-extensions/packages/1825774

Configuring The Client
========
- Configure the Client with either an API Key or OAuth2 Client Credentials: https://github.com/sovity/edc-extensions/tree/main/extensions/wrapper/clients/java-client#usage

- Configure the Client with either an API Key or OAuth2 Client
Credentials: https://github.com/sovity/edc-extensions/tree/main/extensions/wrapper/clients/java-client#usage
- Your management API URL should look like https://your-connector-name.prod-sovity.azure.sovity.io/control/data

Using The Client
========
Feel free to use the endpoints of the aforementioned API groups.
Example Usage of a Use Case API Endpoint:
```java
KpiResult kpiResult = client.useCaseApi().getKpis();
```

A full example providing and consuming a data offer using the API Wrapper Client Library can be found
in [ApiWrapperDemoTest.java](../../../launchers/connectors/sovity-dev/src/test/java/de/sovity/edc/e2e/ApiWrapperDemoTest.java).
3 changes: 3 additions & 0 deletions extensions/wrapper/clients/java-client-example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

Example Quarkus Application that uses the Java API Client Library.

A full example providing and consuming a data offer using the API Wrapper Client Library can be found
in [ApiWrapperDemoTest.java](../../../../launchers/connectors/sovity-dev/src/test/java/de/sovity/edc/e2e/ApiWrapperDemoTest.java).

## License

Apache License 2.0 - see [LICENSE](../../../../LICENSE)
Expand Down
5 changes: 5 additions & 0 deletions extensions/wrapper/clients/java-client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ An example project using this client can be found [here](../java-client-example)

## Usage

### Example Consuming and Providing a Data Offer

A full example providing and consuming a data offer using the API Wrapper Client Library can be found
in [ApiWrapperDemoTest.java](../../../../launchers/connectors/sovity-dev/src/test/java/de/sovity/edc/e2e/ApiWrapperDemoTest.java).

### Example Using API Key Auth

```java
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
/*
* Copyright (c) 2023 sovity GmbH
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* sovity GmbH - init
*/

package de.sovity.edc.e2e;

import de.sovity.edc.client.EdcClient;
import de.sovity.edc.client.gen.model.ContractDefinitionRequest;
import de.sovity.edc.client.gen.model.ContractNegotiationRequest;
import de.sovity.edc.client.gen.model.ContractNegotiationSimplifiedState;
import de.sovity.edc.client.gen.model.InitiateTransferRequest;
import de.sovity.edc.client.gen.model.OperatorDto;
import de.sovity.edc.client.gen.model.PolicyDefinitionCreateRequest;
import de.sovity.edc.client.gen.model.UiAssetCreateRequest;
import de.sovity.edc.client.gen.model.UiContractNegotiation;
import de.sovity.edc.client.gen.model.UiContractOffer;
import de.sovity.edc.client.gen.model.UiCriterion;
import de.sovity.edc.client.gen.model.UiCriterionLiteral;
import de.sovity.edc.client.gen.model.UiCriterionLiteralType;
import de.sovity.edc.client.gen.model.UiCriterionOperator;
import de.sovity.edc.client.gen.model.UiDataOffer;
import de.sovity.edc.client.gen.model.UiPolicyConstraint;
import de.sovity.edc.client.gen.model.UiPolicyCreateRequest;
import de.sovity.edc.client.gen.model.UiPolicyLiteral;
import de.sovity.edc.client.gen.model.UiPolicyLiteralType;
import de.sovity.edc.extension.e2e.connector.ConnectorRemote;
import de.sovity.edc.extension.e2e.connector.MockDataAddressRemote;
import de.sovity.edc.extension.e2e.db.TestDatabase;
import de.sovity.edc.extension.e2e.db.TestDatabaseFactory;
import de.sovity.edc.utils.jsonld.vocab.Prop;
import org.awaitility.Awaitility;
import org.eclipse.edc.junit.extensions.EdcExtension;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import java.time.OffsetDateTime;
import java.util.List;
import java.util.Map;

import static de.sovity.edc.extension.e2e.connector.DataTransferTestUtil.validateDataTransferred;
import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase;
import static de.sovity.edc.extension.e2e.connector.config.ConnectorRemoteConfigFactory.fromConnectorConfig;
import static org.assertj.core.api.Assertions.assertThat;

class ApiWrapperDemoTest {

private static final String PROVIDER_PARTICIPANT_ID = "provider";
private static final String CONSUMER_PARTICIPANT_ID = "consumer";

@RegisterExtension
static EdcExtension providerEdcContext = new EdcExtension();
@RegisterExtension
static EdcExtension consumerEdcContext = new EdcExtension();

@RegisterExtension
static final TestDatabase PROVIDER_DATABASE = TestDatabaseFactory.getTestDatabase(1);
@RegisterExtension
static final TestDatabase CONSUMER_DATABASE = TestDatabaseFactory.getTestDatabase(2);

private ConnectorRemote providerConnector;
private ConnectorRemote consumerConnector;

private EdcClient providerClient;
private EdcClient consumerClient;
private MockDataAddressRemote dataAddress;
private final String dataOfferData = "expected data 123";

private final String dataOfferId = "my-data-offer-2023-11";

@BeforeEach
void setup() {
// set up provider EDC + Client
var providerConfig = forTestDatabase(PROVIDER_PARTICIPANT_ID, 21000, PROVIDER_DATABASE);
providerEdcContext.setConfiguration(providerConfig.getProperties());
providerConnector = new ConnectorRemote(fromConnectorConfig(providerConfig));

providerClient = EdcClient.builder()
.managementApiUrl(providerConfig.getManagementEndpoint().getUri().toString())
.managementApiKey(providerConfig.getProperties().get("edc.api.auth.key"))
.build();

// set up consumer EDC + Client
var consumerConfig = forTestDatabase(CONSUMER_PARTICIPANT_ID, 23000, CONSUMER_DATABASE);
consumerEdcContext.setConfiguration(consumerConfig.getProperties());
consumerConnector = new ConnectorRemote(fromConnectorConfig(consumerConfig));

consumerClient = EdcClient.builder()
.managementApiUrl(consumerConfig.getManagementEndpoint().getUri().toString())
.managementApiKey(consumerConfig.getProperties().get("edc.api.auth.key"))
.build();

// We use the provider EDC as data sink / data source (it has the test-backend-controller extension)
dataAddress = new MockDataAddressRemote(providerConnector.getConfig().getDefaultEndpoint());
}

@Test
void provide_and_consume() {
// provider: create data offer
createPolicy();
createAsset();
createContractDefinition();

// consumer: negotiate contract and transfer data
var dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(getProtocolEndpoint(providerConnector));
var negotiation = initiateNegotiation(dataOffers.get(0), dataOffers.get(0).getContractOffers().get(0));
negotiation = awaitNegotiationDone(negotiation.getContractNegotiationId());
initiateTransfer(negotiation);

// check data sink
validateDataTransferred(dataAddress.getDataSinkSpyUrl(), dataOfferData);
}

private void createAsset() {
var asset = UiAssetCreateRequest.builder()
.id(dataOfferId)
.title("My Data Offer")
.description("Example Data Offer.")
.version("2023-11")
.language("EN")
.publisherHomepage("https://my-department.my-org.com/my-data-offer")
.licenseUrl("https://my-department.my-org.com/my-data-offer#license")
.dataAddressProperties(Map.of(
Prop.Edc.TYPE, "HttpData",
Prop.Edc.METHOD, "GET",
Prop.Edc.BASE_URL, dataAddress.getDataSourceUrl(dataOfferData)
))
.build();

providerClient.uiApi().createAsset(asset);
}

private void createPolicy() {
var afterYesterday = UiPolicyConstraint.builder()
.left("POLICY_EVALUATION_TIME")
.operator(OperatorDto.GT)
.right(UiPolicyLiteral.builder()
.type(UiPolicyLiteralType.STRING)
.value(OffsetDateTime.now().minusDays(1).toString())
.build())
.build();

var beforeTomorrow = UiPolicyConstraint.builder()
.left("POLICY_EVALUATION_TIME")
.operator(OperatorDto.LT)
.right(UiPolicyLiteral.builder()
.type(UiPolicyLiteralType.STRING)
.value(OffsetDateTime.now().plusDays(1).toString())
.build())
.build();

var policyDefinition = PolicyDefinitionCreateRequest.builder()
.policyDefinitionId(dataOfferId)
.policy(UiPolicyCreateRequest.builder()
.constraints(List.of(afterYesterday, beforeTomorrow))
.build())
.build();

providerClient.uiApi().createPolicyDefinition(policyDefinition);
}

private void createContractDefinition() {
var contractDefinition = ContractDefinitionRequest.builder()
.contractDefinitionId(dataOfferId)
.accessPolicyId(dataOfferId)
.contractPolicyId(dataOfferId)
.assetSelector(List.of(UiCriterion.builder()
.operandLeft(Prop.Edc.ID)
.operator(UiCriterionOperator.EQ)
.operandRight(UiCriterionLiteral.builder()
.type(UiCriterionLiteralType.VALUE)
.value(dataOfferId)
.build())
.build()))
.build();

providerClient.uiApi().createContractDefinition(contractDefinition);
}

private UiContractNegotiation initiateNegotiation(UiDataOffer dataOffer, UiContractOffer contractOffer) {
var negotiationRequest = ContractNegotiationRequest.builder()
.counterPartyAddress(dataOffer.getEndpoint())
.counterPartyParticipantId(dataOffer.getParticipantId())
.assetId(dataOffer.getAsset().getAssetId())
.contractOfferId(contractOffer.getContractOfferId())
.policyJsonLd(contractOffer.getPolicy().getPolicyJsonLd())
.build();

return consumerClient.uiApi().initiateContractNegotiation(negotiationRequest);
}

private UiContractNegotiation awaitNegotiationDone(String negotiationId) {
var negotiation = Awaitility.await().atMost(consumerConnector.timeout).until(
() -> consumerClient.uiApi().getContractNegotiation(negotiationId),
it -> it.getState().getSimplifiedState() != ContractNegotiationSimplifiedState.IN_PROGRESS
);

assertThat(negotiation.getState().getSimplifiedState()).isEqualTo(ContractNegotiationSimplifiedState.AGREED);
return negotiation;
}

private void initiateTransfer(UiContractNegotiation negotiation) {
var contractAgreementId = negotiation.getContractAgreementId();
var transferRequest = InitiateTransferRequest.builder()
.contractAgreementId(contractAgreementId)
.dataSinkProperties(dataAddress.getDataSinkProperties())
.build();
consumerClient.uiApi().initiateTransfer(transferRequest);
}

private String getProtocolEndpoint(ConnectorRemote connector) {
return connector.getConfig().getProtocolEndpoint().getUri().toString();
}
}

0 comments on commit 6037905

Please sign in to comment.