Skip to content
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
2 changes: 2 additions & 0 deletions doc/release-notes/expose-export-formats.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# New API method for listing the available exporters
Found at `/api/info/exportFormats`, produces an object with available format names as keys, and as values an object with various info about the exporter. See also #10739.
29 changes: 29 additions & 0 deletions doc/sphinx-guides/source/api/native-api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4858,6 +4858,35 @@ The fully expanded example above (without environment variables) looks like this

curl "https://demo.dataverse.org/api/info/settings/:MaxEmbargoDurationInMonths"

Get Export Formats
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Get the available export formats, including custom formats.

The response contains an object with available format names as keys, and as values an object with the following properties:

* ``displayName``
* ``mediaType``
* ``isHarvestable``
* ``isVisibleInUserInterface`` (corresponds to isAvailableToUsers)
* ``XMLNameSpace`` (only for XML exporters)
* ``XMLSchemaLocation`` (only for XML exporters)
* ``XMLSchemaVersion`` (only for XML exporters)

.. note:: See :ref:`curl-examples-and-environment-variables` if you are unfamiliar with the use of export below.

.. code-block:: bash

export SERVER_URL=https://demo.dataverse.org

curl "$SERVER_URL/api/info/exportFormats"

The fully expanded example above (without environment variables) looks like this:

.. code-block:: bash

curl "https://demo.dataverse.org/api/info/exportFormats"

.. _metadata-blocks-api:

Metadata Blocks
Expand Down
31 changes: 31 additions & 0 deletions src/main/java/edu/harvard/iq/dataverse/api/Info.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,17 @@
import jakarta.ws.rs.Produces;
import org.apache.commons.io.IOUtils;

import edu.harvard.iq.dataverse.export.ExportService;
import edu.harvard.iq.dataverse.settings.JvmSettings;
import edu.harvard.iq.dataverse.settings.SettingsServiceBean;
import edu.harvard.iq.dataverse.util.BundleUtil;
import edu.harvard.iq.dataverse.util.SystemConfig;
import io.gdcc.spi.export.Exporter;
import io.gdcc.spi.export.ExportException;
import io.gdcc.spi.export.XMLExporter;
import jakarta.ejb.EJB;
import jakarta.json.Json;
import jakarta.json.JsonObjectBuilder;
import jakarta.json.JsonValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
Expand Down Expand Up @@ -92,6 +97,32 @@ public Response getZipDownloadLimit() {
return ok(zipDownloadLimit);
}

@GET
@Path("exportFormats")
public Response getExportFormats() {
JsonObjectBuilder responseModel = Json.createObjectBuilder();
ExportService instance = ExportService.getInstance();
for (String[] labels : instance.getExportersLabels()) {
try {
Exporter exporter = instance.getExporter(labels[1]);
Comment on lines +105 to +107
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This lookup seems a bit awkward but it's not your fault. I wonder if we should add a method to ExportService like this...

public Collection<Exporter> getExporters() {
    return exporterMap.values();
}

... so that it can be used like this in places like Info.java:

for (Exporter exporter : instance.getExporters()) {
    //...
}

But I dunno. Maybe there's a reason why we don't offer a "getExporters" method like this.

Copy link
Contributor Author

@julian-schneider julian-schneider Nov 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that the steps I had to use to get the exporters were a bit awkward. If you think it would be in scope, I can add a method like that to this PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, let's think about it outside this PR. You're welcome to create an issue, though, if you like!

JsonObjectBuilder exporterObject = Json.createObjectBuilder().add("displayName", labels[0])
.add("mediaType", exporter.getMediaType()).add("isHarvestable", exporter.isHarvestable())
.add("isVisibleInUserInterface", exporter.isAvailableToUsers());
if (exporter instanceof XMLExporter xmlExporter) {
exporterObject.add("XMLNameSpace", xmlExporter.getXMLNameSpace())
.add("XMLSchemaLocation", xmlExporter.getXMLSchemaLocation())
.add("XMLSchemaVersion", xmlExporter.getXMLSchemaVersion());
}
responseModel.add(labels[1], exporterObject);
}
catch (ExportException ex){
logger.warning("Failed to get: " + labels[1]);
logger.warning(ex.getLocalizedMessage());
}
}
return ok(responseModel);
}

private Response getSettingResponseByKey(SettingsServiceBean.Key key) {
String setting = settingsService.getValueForKey(key);
if (setting != null) {
Expand Down
21 changes: 20 additions & 1 deletion src/test/java/edu/harvard/iq/dataverse/api/InfoIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static jakarta.ws.rs.core.Response.Status.BAD_REQUEST;
import static jakarta.ws.rs.core.Response.Status.NOT_FOUND;
import static jakarta.ws.rs.core.Response.Status.OK;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.notNullValue;
import org.skyscreamer.jsonassert.JSONAssert;

public class InfoIT {

Expand Down Expand Up @@ -81,6 +84,22 @@ public void testGetZipDownloadLimit() {
.body("data", notNullValue());
}

@Test
public void testGetExportFormats() throws IOException {
Response response = given().urlEncodingEnabled(false)
.get("/api/info/exportFormats");
response.prettyPrint();
response.then().assertThat().statusCode(OK.getStatusCode());

String actual = response.getBody().asString();
String expected =
java.nio.file.Files.readString(
Paths.get("src/test/resources/json/export-formats.json"),
StandardCharsets.UTF_8);
JSONAssert.assertEquals(expected, actual, true);

}


private void testSettingEndpoint(SettingsServiceBean.Key settingKey, String testSettingValue) {
String endpoint = "/api/info/settings/" + settingKey;
Expand Down
83 changes: 83 additions & 0 deletions src/test/resources/json/export-formats.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
{
"status": "OK",
"data": {
"OAI_ORE": {
"displayName": "OAI_ORE",
"mediaType": "application/json",
"isHarvestable": false,
"isVisibleInUserInterface": true
},
"Datacite": {
"displayName": "DataCite",
"mediaType": "application/xml",
"isHarvestable": true,
"isVisibleInUserInterface": true,
"XMLNameSpace": "http://datacite.org/schema/kernel-4",
"XMLSchemaLocation": "http://datacite.org/schema/kernel-4 http://schema.datacite.org/meta/kernel-4.5/metadata.xsd",
"XMLSchemaVersion": "4.5"
},
"oai_dc": {
"displayName": "Dublin Core",
"mediaType": "application/xml",
"isHarvestable": true,
"isVisibleInUserInterface": false,
"XMLNameSpace": "http://www.openarchives.org/OAI/2.0/oai_dc/",
"XMLSchemaLocation": "http://www.openarchives.org/OAI/2.0/oai_dc.xsd",
"XMLSchemaVersion": "2.0"
},
"oai_datacite": {
"displayName": "OpenAIRE",
"mediaType": "application/xml",
"isHarvestable": true,
"isVisibleInUserInterface": true,
"XMLNameSpace": "http://datacite.org/schema/kernel-4",
"XMLSchemaLocation": "http://schema.datacite.org/meta/kernel-4.1/metadata.xsd",
"XMLSchemaVersion": "4.1"
},
"schema.org": {
"displayName": "Schema.org JSON-LD",
"mediaType": "application/json",
"isHarvestable": false,
"isVisibleInUserInterface": true
},
"ddi": {
"displayName": "DDI Codebook v2",
"mediaType": "application/xml",
"isHarvestable": false,
"isVisibleInUserInterface": true,
"XMLNameSpace": "ddi:codebook:2_5",
"XMLSchemaLocation": "https://ddialliance.org/Specification/DDI-Codebook/2.5/XMLSchema/codebook.xsd",
"XMLSchemaVersion": "2.5"
},
"dcterms": {
"displayName": "Dublin Core",
"mediaType": "application/xml",
"isHarvestable": false,
"isVisibleInUserInterface": true,
"XMLNameSpace": "http://purl.org/dc/terms/",
"XMLSchemaLocation": "http://dublincore.org/schemas/xmls/qdc/dcterms.xsd",
"XMLSchemaVersion": "2.0"
},
"html": {
"displayName": "DDI HTML Codebook",
"mediaType": "text/html",
"isHarvestable": false,
"isVisibleInUserInterface": true
},
"dataverse_json": {
"displayName": "JSON",
"mediaType": "application/json",
"isHarvestable": true,
"isVisibleInUserInterface": true
},
"oai_ddi": {
"displayName": "DDI Codebook v2",
"mediaType": "application/xml",
"isHarvestable": true,
"isVisibleInUserInterface": false,
"XMLNameSpace": "ddi:codebook:2_5",
"XMLSchemaLocation": "https://ddialliance.org/Specification/DDI-Codebook/2.5/XMLSchema/codebook.xsd",
"XMLSchemaVersion": "2.5"
}
}
}