Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add catalog endpoints schema examples #3306

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public Stream<JsonObject> extract(JsonObject object, JsonLdPath path) {
public Stream<JsonObject> extract(JsonObject object, JsonLdPath path) {
var array = object.getJsonArray(path.last());

if (array == null) {
if (array == null || array.isEmpty()) {
return Stream.empty();
} else {
return Stream.of(array.getJsonObject(0));
Expand Down
2 changes: 1 addition & 1 deletion docs/developer/custom_validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ themselves.
## When to use it

This feature is intended for use cases where the standard DTO validation, that ships with EDC's APIs is not sufficient.
Please check out the [OpenAPI spec](../../resources/openapi/openapi.yaml) to find out more about the object schema.
Please check out the [OpenAPI spec](../../resources/openapi/yaml) to find out more about the object schema.

EDC features various data types that do not have a strict schema but are *extensible*, for example `Asset`/`AssetDto`,
or a `DataRequest`/`DataRequestDto`. This was done by design, to allow for maximum flexibility and openness. However,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ record CriterionSchema(
public static final String CRITERION_EXAMPLE = """
{
"@context": { "edc": "https://w3id.org/edc/v0.0.1/ns/" },
"@type": "Criterion",
"operandLeft": "fieldName",
"operator": "=",
"operandRight": "some value"
Expand All @@ -57,11 +58,12 @@ record QuerySpecSchema(
public static final String QUERY_SPEC_EXAMPLE = """
{
"@context": { "edc": "https://w3id.org/edc/v0.0.1/ns/" },
"@type": "QuerySpec",
"offset": 5,
"limit": 10,
"sortOrder": "DESC",
"sortField": "fieldName",
"criterion": []
"filterExpression": []
}
""";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ record ContractAgreementSchema(
long contractSigningDate,
String assetId,
@Schema(description = "ODRL policy")
Object policy
PolicySchema policy
) {
public static final String CONTRACT_AGREEMENT_EXAMPLE = """
{
Expand Down Expand Up @@ -81,5 +81,30 @@ record DataAddressSchema(
String type,
@Schema(name = "type")
String typeProperty
) { }
) {
}

@Schema(description = "ODRL policy", example = PolicySchema.POLICY_EXAMPLE)
record PolicySchema() {
public static final String POLICY_EXAMPLE = """
{
"@context": "http://www.w3.org/ns/odrl.jsonld",
"@id": "0949ba30-680c-44e6-bc7d-1688cbe1847e",
"@type": "odrl:Set",
"permission": {
"target": "http://example.com/asset:9898.movie",
"action": {
"type": "http://www.w3.org/ns/odrl/2/use"
},
"constraint": {
"leftOperand": "https://w3id.org/edc/v0.0.1/ns/left",
"operator": "eq",
"rightOperand": "value"
}
},
"prohibition": [],
"obligation": []
}
""";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.eclipse.edc.connector.api.management.configuration.ManagementApiSchema.ContractAgreementSchema.CONTRACT_AGREEMENT_EXAMPLE;
import static org.eclipse.edc.connector.api.management.configuration.ManagementApiSchema.PolicySchema.POLICY_EXAMPLE;
import static org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement.CONTRACT_AGREEMENT_ASSET_ID;
import static org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement.CONTRACT_AGREEMENT_CONSUMER_ID;
import static org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement.CONTRACT_AGREEMENT_POLICY;
Expand All @@ -33,6 +34,7 @@
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.VALUE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_PERMISSION_ATTRIBUTE;
import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat;
import static org.eclipse.edc.junit.extensions.TestServiceExtensionContext.testServiceExtensionContext;

Expand All @@ -57,4 +59,16 @@ void contractAgreementExample() throws JsonProcessingException {
});
}

@Test
void policyExample() throws JsonProcessingException {
var jsonObject = objectMapper.readValue(POLICY_EXAMPLE, JsonObject.class);
var expanded = jsonLd.expand(jsonObject);

assertThat(expanded).isSucceeded().satisfies(content -> {
assertThat(content.getString(ID)).isNotBlank();
assertThat(content.getJsonArray(TYPE).getString(0)).isNotBlank();
assertThat(content.getJsonArray(ODRL_PERMISSION_ATTRIBUTE).size()).isGreaterThan(0);
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ dependencies {

implementation(libs.jakarta.rsApi)

testImplementation(project(":extensions:common:http"))
testImplementation(project(":extensions:common:iam:iam-mock"))

testImplementation(project(":core:common:junit"))
testImplementation(project(":core:common:transform-core"))
testImplementation(project(":core:control-plane:control-plane-core"))
testImplementation(project(":core:data-plane-selector:data-plane-selector-core"))
testImplementation(project(":extensions:common:http"))
testImplementation(project(":extensions:common:iam:iam-mock"))
testImplementation(testFixtures(project(":extensions:common:http:jersey-core")))
testImplementation(libs.restAssured)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,118 @@
import jakarta.json.JsonObject;
import jakarta.ws.rs.container.AsyncResponse;
import jakarta.ws.rs.container.Suspended;
import org.eclipse.edc.catalog.spi.Catalog;
import org.eclipse.edc.connector.api.management.catalog.model.CatalogRequestDto;
import org.eclipse.edc.api.model.ApiCoreSchema;

import static org.eclipse.edc.catalog.spi.CatalogRequest.CATALOG_REQUEST_TYPE;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE;

@OpenAPIDefinition
@Tag(name = "Catalog")
public interface CatalogApi {

@Operation(
requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = CatalogRequestDto.class))),
requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = CatalogRequestSchema.class))),
responses = { @ApiResponse(
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Catalog.class)
schema = @Schema(implementation = CatalogSchema.class)
),
description = "Gets contract offers (=catalog) of a single connector") }
)
void requestCatalog(JsonObject requestDto, @Suspended AsyncResponse response);
void requestCatalog(JsonObject request, @Suspended AsyncResponse response);

@Schema(example = CatalogRequestSchema.CATALOG_REQUEST_EXAMPLE)
record CatalogRequestSchema(
@Schema(name = TYPE, example = CATALOG_REQUEST_TYPE)
String providerUrl,
String protocol,
ApiCoreSchema.QuerySpecSchema querySpec) {

public static final String CATALOG_REQUEST_EXAMPLE = """
{
"@context": { "edc": "https://w3id.org/edc/v0.0.1/ns/" },
"@type": "CatalogRequest",
"providerUrl": "http://provider-address",
"protocol": "dataspace-protocol-http",
"querySpec": {
"offset": 0,
"limit": 50,
"sortOrder": "DESC",
"sortField": "fieldName",
"filterExpression": []
}
}
""";
}

@Schema(description = "DCAT catalog", example = CatalogSchema.CATALOG_EXAMPLE)
record CatalogSchema(
) {
public static final String CATALOG_EXAMPLE = """
{
"@id": "7df65569-8c59-4013-b1c0-fa14f6641bf2",
"@type": "dcat:Catalog",
"dcat:dataset": {
"@id": "bcca61be-e82e-4da6-bfec-9716a56cef35",
"@type": "dcat:Dataset",
"odrl:hasPolicy": {
"@id": "OGU0ZTMzMGMtODQ2ZS00ZWMxLThmOGQtNWQxNWM0NmI2NmY4:YmNjYTYxYmUtZTgyZS00ZGE2LWJmZWMtOTcxNmE1NmNlZjM1:NDY2ZTZhMmEtNjQ1Yy00ZGQ0LWFlZDktMjdjNGJkZTU4MDNj",
"@type": "odrl:Set",
"odrl:permission": {
"odrl:target": "bcca61be-e82e-4da6-bfec-9716a56cef35",
"odrl:action": {
"odrl:type": "http://www.w3.org/ns/odrl/2/use"
},
"odrl:constraint": {
"odrl:and": [
{
"odrl:leftOperand": "https://w3id.org/edc/v0.0.1/ns/inForceDate",
"odrl:operator": {
"@id": "odrl:gteq"
},
"odrl:rightOperand": "2023-07-07T07:19:58.585601395Z"
},
{
"odrl:leftOperand": "https://w3id.org/edc/v0.0.1/ns/inForceDate",
"odrl:operator": {
"@id": "odrl:lteq"
},
"odrl:rightOperand": "2023-07-12T07:19:58.585601395Z"
}
]
}
},
"odrl:prohibition": [],
"odrl:obligation": [],
"odrl:target": "bcca61be-e82e-4da6-bfec-9716a56cef35"
},
"dcat:distribution": [
{
"@type": "dcat:Distribution",
"dct:format": {
"@id": "HttpData"
},
"dcat:accessService": "5e839777-d93e-4785-8972-1005f51cf367"
}
],
"edc:description": "description",
"edc:id": "bcca61be-e82e-4da6-bfec-9716a56cef35"
},
"dcat:service": {
"@id": "5e839777-d93e-4785-8972-1005f51cf367",
"@type": "dcat:DataService",
"dct:terms": "connector",
"dct:endpointUrl": "http://localhost:16806/protocol"
},
"edc:participantId": "urn:connector:provider",
"@context": {
"dct": "https://purl.org/dc/terms/",
"edc": "https://w3id.org/edc/v0.0.1/ns/",
"dcat": "https://www.w3.org/ns/dcat/",
"odrl": "http://www.w3.org/ns/odrl/2/",
"dspace": "https://w3id.org/dspace/v0.8/"
}
}
""";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import jakarta.ws.rs.container.AsyncResponse;
import jakarta.ws.rs.container.Suspended;
import org.eclipse.edc.catalog.spi.CatalogRequest;
import org.eclipse.edc.connector.api.management.catalog.model.CatalogRequestDto;
import org.eclipse.edc.connector.spi.catalog.CatalogService;
import org.eclipse.edc.spi.EdcException;
import org.eclipse.edc.transform.spi.TypeTransformerRegistry;
Expand All @@ -32,7 +31,7 @@
import org.eclipse.edc.web.spi.exception.ValidationFailureException;

import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
import static org.eclipse.edc.catalog.spi.CatalogRequest.EDC_CATALOG_REQUEST_TYPE;
import static org.eclipse.edc.catalog.spi.CatalogRequest.CATALOG_REQUEST_TYPE;

@Path("/v2/catalog")
@Consumes(APPLICATION_JSON)
Expand All @@ -54,10 +53,9 @@ public CatalogApiController(CatalogService service, TypeTransformerRegistry tran
@POST
@Path("/request")
public void requestCatalog(JsonObject requestBody, @Suspended AsyncResponse response) {
validatorRegistry.validate(EDC_CATALOG_REQUEST_TYPE, requestBody).orElseThrow(ValidationFailureException::new);
validatorRegistry.validate(CATALOG_REQUEST_TYPE, requestBody).orElseThrow(ValidationFailureException::new);

var request = transformerRegistry.transform(requestBody, CatalogRequestDto.class)
.compose(dto -> transformerRegistry.transform(dto, CatalogRequest.class))
var request = transformerRegistry.transform(requestBody, CatalogRequest.class)
.orElseThrow(InvalidRequestException::new);

service.request(request.getProviderUrl(), request.getProtocol(), request.getQuerySpec())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
package org.eclipse.edc.connector.api.management.catalog;

import org.eclipse.edc.catalog.spi.CatalogRequest;
import org.eclipse.edc.connector.api.management.catalog.transform.CatalogRequestDtoToCatalogRequestTransformer;
import org.eclipse.edc.connector.api.management.catalog.transform.JsonObjectToCatalogRequestDtoTransformer;
import org.eclipse.edc.connector.api.management.catalog.transform.JsonObjectToCatalogRequestTransformer;
import org.eclipse.edc.connector.api.management.catalog.validation.CatalogRequestValidator;
import org.eclipse.edc.connector.api.management.configuration.ManagementApiConfiguration;
import org.eclipse.edc.connector.api.management.configuration.transform.ManagementApiTypeTransformerRegistry;
Expand Down Expand Up @@ -55,11 +54,10 @@ public String name() {

@Override
public void initialize(ServiceExtensionContext context) {
transformerRegistry.register(new CatalogRequestDtoToCatalogRequestTransformer());
transformerRegistry.register(new JsonObjectToCatalogRequestDtoTransformer());
transformerRegistry.register(new JsonObjectToCatalogRequestTransformer());

webService.registerResource(config.getContextAlias(), new CatalogApiController(service, transformerRegistry, validatorRegistry));

validatorRegistry.register(CatalogRequest.EDC_CATALOG_REQUEST_TYPE, CatalogRequestValidator.instance());
validatorRegistry.register(CatalogRequest.CATALOG_REQUEST_TYPE, CatalogRequestValidator.instance());
}
}

This file was deleted.

Loading
Loading