Skip to content

Commit

Permalink
feat: #3 add retrieve dataset endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
brunopacheco1 committed Apr 8, 2024
1 parent 2bf215b commit b1cab29
Show file tree
Hide file tree
Showing 19 changed files with 657 additions and 20 deletions.
3 changes: 3 additions & 0 deletions _http/ckan.http
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ GET https://ckan-test.healthdata.nl/api/3/action/package_search?fq=&sort=score+d

###
GET https://ckan-test.healthdata.nl/api/3/action/package_show?id=e1b3eff9-13eb-48b0-b180-7ecb76b84454

###
GET https://ckan-test.healthdata.nl/api/3/action/package_show?id=dummy
3 changes: 3 additions & 0 deletions _http/discovery.http
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,8 @@ Content-Type: application/json
}]
}

###
GET http://localhost:8080/api/v1/datasets/e1b3eff9-13eb-48b0-b180-7ecb76b84454

###
GET http://localhost:8080/api/v1/datasets/dummy
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-FileCopyrightText: 2024 PNED G.I.E.
//
// SPDX-License-Identifier: Apache-2.0

package io.github.genomicdatainfrastructure.discovery.api;

import static jakarta.ws.rs.core.Response.Status.NOT_FOUND;

import io.github.genomicdatainfrastructure.discovery.exceptions.DatasetNotFoundException;
import io.github.genomicdatainfrastructure.discovery.model.ErrorResponse;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Provider;

@Provider
public class DatasetNotFoundExceptionMapper implements
ExceptionMapper<DatasetNotFoundException> {

@Override
public Response toResponse(DatasetNotFoundException exception) {
var errorResponse = new ErrorResponse(
"Dataset Not Found",
NOT_FOUND.getStatusCode(),
exception.getMessage()
);

return Response
.status(NOT_FOUND)
.entity(errorResponse)
.type(MediaType.APPLICATION_JSON)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import io.github.genomicdatainfrastructure.discovery.model.DatasetsSearchResponse;
import io.github.genomicdatainfrastructure.discovery.model.RetrievedDataset;
import io.github.genomicdatainfrastructure.discovery.services.DatasetsSearchService;
import io.github.genomicdatainfrastructure.discovery.services.RetrieveDatasetService;
import io.quarkus.oidc.runtime.OidcJwtCallerPrincipal;
import io.quarkus.security.identity.SecurityIdentity;
import lombok.RequiredArgsConstructor;
Expand All @@ -17,16 +18,16 @@ public class DatasetQueryApiImpl implements DatasetQueryApi {

private final SecurityIdentity identity;
private final DatasetsSearchService datasetsSearchService;
private final RetrieveDatasetService retrievedDatasetService;

@Override
public DatasetsSearchResponse datasetSearch(DatasetSearchQuery datasetSearchQuery) {
return datasetsSearchService.search(accessToken(), datasetSearchQuery);
return datasetsSearchService.search(datasetSearchQuery, accessToken());
}

@Override
public RetrievedDataset retrieveDataset(String id) {
return RetrievedDataset.builder()
.build();
return retrievedDatasetService.retrieve(id, accessToken());
}

private String accessToken() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: 2024 PNED G.I.E.
//
// SPDX-License-Identifier: Apache-2.0

package io.github.genomicdatainfrastructure.discovery.exceptions;

public class DatasetNotFoundException extends RuntimeException {

private static final String MESSAGE = "Dataset %s not found";

public DatasetNotFoundException(String datasetId) {
super(MESSAGE.formatted(datasetId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public DatasetsSearchService(
this.ckanQueryApi = ckanQueryApi;
}

public DatasetsSearchResponse search(String accessToken, DatasetSearchQuery query) {
public DatasetsSearchResponse search(DatasetSearchQuery query, String accessToken) {
var response = ckanQueryApi.packageSearch(
query.getQuery(),
CkanFacetsQueryBuilder.buildFacetQuery(query.getFacets()),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// SPDX-FileCopyrightText: 2024 PNED G.I.E.
//
// SPDX-License-Identifier: Apache-2.0

package io.github.genomicdatainfrastructure.discovery.services;

import java.util.List;
import java.util.Objects;

import io.github.genomicdatainfrastructure.discovery.model.RetrievedDataset;
import io.github.genomicdatainfrastructure.discovery.model.RetrievedDistribution;
import io.github.genomicdatainfrastructure.discovery.model.ValueLabel;
import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.CkanOrganization;
import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.CkanPackage;
import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.CkanResource;

import static java.util.Optional.ofNullable;
import static java.util.function.Predicate.not;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class PackageShowMapper {

public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern(
"yyyy-MM-dd'T'HH:mm:ss.SSSSSS"
);

private PackageShowMapper() {
// Utility class
}

public static RetrievedDataset from(CkanPackage ckanPackage) {
var catalogue = ofNullable(ckanPackage.getOrganization())
.map(CkanOrganization::getTitle)
.orElse(null);

return RetrievedDataset.builder()
.id(ckanPackage.getId())
.identifier(ckanPackage.getIdentifier())
.title(ckanPackage.getName())
.description(ckanPackage.getNotes())
.themes(values(ckanPackage.getTheme()))
.publisherName(ckanPackage.getPublisherName())
.catalogue(catalogue)
.createdAt(parse(ckanPackage.getMetadataCreated()))
.modifiedAt(parse(ckanPackage.getMetadataModified()))
.url(ckanPackage.getUrl())
.languages(values(ckanPackage.getLanguage()))
.contact(value(ckanPackage.getContactUri()))
.hasVersions(values(ckanPackage.getHasVersion()))
.accessRights(value(ckanPackage.getAccessRights()))
.conformsTo(values(ckanPackage.getConformsTo()))
.provenance(ckanPackage.getProvenance())
.spatial(value(ckanPackage.getSpatialUri()))
.distributions(distributions(ckanPackage))
.build();
}

private static List<ValueLabel> values(List<String> values) {
return ofNullable(values)
.orElseGet(List::of)
.stream()
.map(PackageShowMapper::value)
.filter(Objects::nonNull)
.toList();
}

private static ValueLabel value(String value) {
return ofNullable(value)
.filter(Objects::nonNull)
.filter(not(String::isBlank))
.map(it -> ValueLabel.builder()
.value(it)
.label(it)
.build())
.orElse(null);
}

private static LocalDateTime parse(String date) {
return ofNullable(date)
.map(it -> LocalDateTime.parse(it, DATE_FORMATTER))
.orElse(null);
}

private static List<RetrievedDistribution> distributions(CkanPackage ckanPackage) {
return ofNullable(ckanPackage.getResources())
.orElseGet(List::of)
.stream()
.map(PackageShowMapper::distribution)
.toList();
}

private static RetrievedDistribution distribution(CkanResource ckanResource) {
return RetrievedDistribution.builder()
.id(ckanResource.getId())
.title(ckanResource.getName())
.description(ckanResource.getDescription())
.format(value(ckanResource.getFormat()))
.uri(ckanResource.getUri())
.createdAt(parse(ckanResource.getCreated()))
.modifiedAt(parse(ckanResource.getLastModified()))
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.PackagesSearchResult;
import java.util.List;
import java.util.Map;

import java.util.Objects;
import java.time.format.DateTimeFormatter;
import java.time.LocalDateTime;

import static java.util.Optional.ofNullable;
import static java.util.function.Predicate.not;

public class PackagesSearchResponseMapper {

Expand Down Expand Up @@ -120,10 +121,19 @@ private static List<ValueLabel> values(List<String> values) {
return ofNullable(values)
.orElseGet(List::of)
.stream()
.map(PackagesSearchResponseMapper::value)
.filter(Objects::nonNull)
.toList();
}

private static ValueLabel value(String value) {
return ofNullable(value)
.filter(Objects::nonNull)
.filter(not(String::isBlank))
.map(it -> ValueLabel.builder()
.value(it)
.label(it)
.build())
.toList();
.orElse(null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// SPDX-FileCopyrightText: 2024 PNED G.I.E.
//
// SPDX-License-Identifier: Apache-2.0

package io.github.genomicdatainfrastructure.discovery.services;

import org.eclipse.microprofile.rest.client.inject.RestClient;

import io.github.genomicdatainfrastructure.discovery.exceptions.DatasetNotFoundException;
import io.github.genomicdatainfrastructure.discovery.model.RetrievedDataset;
import io.github.genomicdatainfrastructure.discovery.remote.ckan.api.CkanQueryApi;
import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.CkanPackageShowResponse;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.WebApplicationException;

@ApplicationScoped
public class RetrieveDatasetService {

private final CkanQueryApi ckanQueryApi;

@Inject
public RetrieveDatasetService(
@RestClient CkanQueryApi ckanQueryApi
) {
this.ckanQueryApi = ckanQueryApi;
}

public RetrievedDataset retrieve(String id, String accessToken) {
var response = retrieveCkanPackage(id, accessToken);
return PackageShowMapper.from(response.getResult());
}

public CkanPackageShowResponse retrieveCkanPackage(String id, String accessToken) {
try {
return ckanQueryApi.packageShow(id, accessToken);
} catch (WebApplicationException e) {
if (e.getResponse().getStatus() == 404) {
throw new DatasetNotFoundException(id);
}
throw e;
}
}
}
31 changes: 30 additions & 1 deletion src/main/openapi/ckan.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,13 @@ paths:
content:
application/json:
schema:
$ref: "#/components/schemas/CkanPackage"
$ref: "#/components/schemas/CkanPackageShowResponse"
"404":
description: The package not found
content:
application/json:
schema:
$ref: "#/components/schemas/CkanErrorResponse"
components:
schemas:
PackagesSearchResponse:
Expand Down Expand Up @@ -232,3 +238,26 @@ components:
- name
- description
- created
CkanPackageShowResponse:
type: object
properties:
help:
type: string
success:
type: boolean
result:
$ref: "#/components/schemas/CkanPackage"
CkanErrorResponse:
type: object
properties:
help:
type: string
success:
type: boolean
error:
type: object
properties:
__type:
type: string
message:
type: string
10 changes: 2 additions & 8 deletions src/main/openapi/discovery.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,6 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/RetrievedDataset"
"403":
description: Dataset is not visible to the user
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"404":
description: Dataset not found
content:
Expand Down Expand Up @@ -229,7 +223,7 @@ components:
hasVersions:
type: array
items:
type: string
$ref: "#/components/schemas/ValueLabel"
title: Has Versions
accessRights:
$ref: "#/components/schemas/ValueLabel"
Expand Down Expand Up @@ -269,7 +263,7 @@ components:
type: string
title: Description
format:
type: string
$ref: "#/components/schemas/ValueLabel"
title: Format
uri:
type: string
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-FileCopyrightText: 2024 PNED G.I.E.
//
// SPDX-License-Identifier: Apache-2.0

package io.github.genomicdatainfrastructure.discovery.api;

import io.quarkus.test.junit.QuarkusIntegrationTest;

@QuarkusIntegrationTest
public class RetrieveDatasetIT extends RetrieveDatasetTest {
}
Loading

0 comments on commit b1cab29

Please sign in to comment.