Skip to content
Permalink
Browse files

feat(api-v2): Add metadata routes (DSP-662) (#1734)

  • Loading branch information
benjamingeer committed Oct 26, 2020
1 parent 9bd749d commit bf489685f012bd28bf189a2f3908eef6717ab513
Showing with 2,544 additions and 726 deletions.
  1. +102 −0 docs/03-apis/api-v2/metadata.md
  2. +7 −25 docs/05-internals/design/api-v2/json-ld.md
  3. +1 −0 webapi/src/main/scala/org/knora/webapi/app/ApplicationActor.scala
  4. +7 −0 webapi/src/main/scala/org/knora/webapi/exceptions/Exceptions.scala
  5. +1 −0 webapi/src/main/scala/org/knora/webapi/messages/BUILD.bazel
  6. +10 −0 webapi/src/main/scala/org/knora/webapi/messages/StringFormatter.scala
  7. +1 −1 ...c/main/scala/org/knora/webapi/messages/admin/responder/projectsmessages/ProjectsMessagesADM.scala
  8. +27 −2 webapi/src/main/scala/org/knora/webapi/messages/store/triplestoremessages/TriplestoreMessages.scala
  9. +538 −7 webapi/src/main/scala/org/knora/webapi/messages/util/JsonLDUtil.scala
  10. +135 −0 webapi/src/main/scala/org/knora/webapi/messages/util/RdfFormatUtil.scala
  11. +21 −0 webapi/src/main/scala/org/knora/webapi/messages/v2/responder/KnoraRequestV2.scala
  12. +99 −7 webapi/src/main/scala/org/knora/webapi/messages/v2/responder/KnoraResponseV2.scala
  13. +3 −3 webapi/src/main/scala/org/knora/webapi/messages/v2/responder/listsmessages/ListsMessagesV2.scala
  14. +95 −0 ...i/src/main/scala/org/knora/webapi/messages/v2/responder/metadatamessages/MetadataMessagesV2.scala
  15. +3 −3 ...i/src/main/scala/org/knora/webapi/messages/v2/responder/ontologymessages/OntologyMessagesV2.scala
  16. +3 −3 ...i/src/main/scala/org/knora/webapi/messages/v2/responder/resourcemessages/ResourceMessagesV2.scala
  17. +1 −1 webapi/src/main/scala/org/knora/webapi/messages/v2/responder/searchmessages/SearchMessagesV2.scala
  18. +3 −3 ...i/src/main/scala/org/knora/webapi/messages/v2/responder/standoffmessages/StandoffMessagesV2.scala
  19. +2 −2 webapi/src/main/scala/org/knora/webapi/messages/v2/responder/valuemessages/ValueMessagesV2.scala
  20. +1 −0 webapi/src/main/scala/org/knora/webapi/responders/BUILD.bazel
  21. +46 −36 webapi/src/main/scala/org/knora/webapi/responders/ResponderManager.scala
  22. +1 −1 webapi/src/main/scala/org/knora/webapi/responders/admin/ProjectsResponderADM.scala
  23. +112 −0 webapi/src/main/scala/org/knora/webapi/responders/v2/MetadataResponderV2.scala
  24. +2 −2 webapi/src/main/scala/org/knora/webapi/responders/v2/SearchResponderV2.scala
  25. +1 −0 webapi/src/main/scala/org/knora/webapi/routing/BUILD.bazel
  26. +28 −1 webapi/src/main/scala/org/knora/webapi/routing/KnoraRoute.scala
  27. +82 −90 webapi/src/main/scala/org/knora/webapi/routing/RouteUtilV2.scala
  28. +96 −0 webapi/src/main/scala/org/knora/webapi/routing/v2/MetadataRouteV2.scala
  29. +0 −160 webapi/src/main/scala/org/knora/webapi/store/triplestore/http/GraphProtocolAccessor.scala
  30. +310 −263 webapi/src/main/scala/org/knora/webapi/store/triplestore/http/HttpTriplestoreConnector.scala
  31. +0 −75 webapi/src/main/scala/org/knora/webapi/util/SparqlUtil.scala
  32. +0 −1 webapi/src/test/scala/org/knora/webapi/CoreSpec.scala
  33. +2 −34 webapi/src/test/scala/org/knora/webapi/E2ESpec.scala
  34. +2 −2 webapi/src/test/scala/org/knora/webapi/R2RSpec.scala
  35. +19 −0 webapi/src/test/scala/org/knora/webapi/e2e/v2/BUILD.bazel
  36. +171 −0 webapi/src/test/scala/org/knora/webapi/e2e/v2/MetadataRouteV2E2ESpec.scala
  37. +39 −0 webapi/src/test/scala/org/knora/webapi/messages/util/BUILD.bazel
  38. +108 −2 webapi/src/test/scala/org/knora/webapi/messages/util/JsonLDUtilSpec.scala
  39. +105 −0 webapi/src/test/scala/org/knora/webapi/messages/util/KnoraResponseV2Spec.scala
  40. +81 −0 webapi/src/test/scala/org/knora/webapi/messages/util/RdfFormatUtilSpec.scala
  41. +23 −0 webapi/src/test/scala/org/knora/webapi/messages/v2/responder/metadatamessages/BUILD.bazel
  42. +62 −0 ...c/test/scala/org/knora/webapi/messages/v2/responder/metadatamessages/MetadataMessagesV2Spec.scala
  43. +19 −0 webapi/src/test/scala/org/knora/webapi/responders/v2/BUILD.bazel
  44. +134 −0 webapi/src/test/scala/org/knora/webapi/responders/v2/MetadataResponderV2Spec.scala
  45. +8 −2 webapi/src/test/scala/org/knora/webapi/sharedtestdata/SharedTestDataADM.scala
  46. +33 −0 webapi/src/test/scala/org/knora/webapi/store/triplestore/AllTriplestoreSpec.scala
@@ -0,0 +1,102 @@
<!---
Copyright © 2015-2019 the contributors (see Contributors.md).
This file is part of Knora.
Knora is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Knora is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public
License along with Knora. If not, see <http://www.gnu.org/licenses/>.
-->

# Metadata Endpoint

## Endpoint Overview

The metadata of a project contains information about its scope, content, contributors, funding, etc. modeled according to
to the [dsp-ontologies](https://github.com/dasch-swiss/dsp-ontologies) data model. Metadata information must be available for
any [DaSCH](http://dasch.swiss/) project so that researchers can go through the projects and get an idea about every project.

## Creating and Updating Project Metadata

Project metadata must correspond to the [dsp-ontologies](https://github.com/dasch-swiss/dsp-ontologies).

To create or update project metadata for a project, submit it in a `PUT` request, specifying the project
IRI in the URL path:

```
PUT http://host/v2/metadata/PROJECT_IRI
```

Currently, all the metadata for a project must be submitted in a single request. The submitted metadata
replaces any metadata that has already been stored for the project. Only an administrator of the project,
or a system administrator, can create or update project metadata.

The metadata can be submitted in **Turtle**, **JSON-LD**, or **RDF/XML** format. The request must
include a `Content-Type` header with one of the following values:

| Format | MIME Type |
|---------|-----------------------|
| JSON-LD | `application/ld+json` |
| Turtle | `text/turtle` |
| RDF/XML | `application/rdf+xml` |

An example request in Turtle format:

```turtle
@prefix dsp-repo: <http://ns.dasch.swiss/repository#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@base <http://ns.dasch.swiss/repository#> .
<beol> rdf:type dsp-repo:Project .
<beol> dsp-repo:hasName "Bernoulli-Euler Online (BEOL)" .
<beol> dsp-repo:hasKeywords "mathematics" .
<beol> dsp-repo:hasKeywords "science" .
<beol> dsp-repo:hasKeywords "history of science" .
<beol> dsp-repo:hasKeywords "history of mathematics" .
<beol> dsp-repo:hasCategories "mathematics" .
<beol> dsp-repo:hasStartDate "2016.07" .
<beol> dsp-repo:hasEndDate "2020.01" .
<beol> dsp-repo:hasFunder "Schweizerischer Nationalfonds (SNSF)" .
```

After successful creation of the metadata graph, the API returns HTTP 200 with a confirmation message.

## Retrieving Project Metadata

Any user can retrieve the metadata information for a project by providing its IRI in a `GET` request:

```
GET http://host/v2/metadata/PROJECT_IRI
```

The metadata can be returned in any of the formats listed in the previous section. By default, JSON-LD
is returned. To request another format, specify it in the `Accept` header of the request.

An example response in JSON-LD format:

```json
{
"http://ns.dasch.swiss/repository#hasName": "Bernoulli-Euler Online (BEOL)",
"http://ns.dasch.swiss/repository#hasFunder": "Schweizerischer Nationalfonds (SNSF)",
"http://ns.dasch.swiss/repository#hasKeywords": [
"science",
"mathematics",
"history of science",
"history of mathematics"
],
"http://ns.dasch.swiss/repository#hasEndDate": "2020.01",
"http://ns.dasch.swiss/repository#hasCategories": "mathematics",
"@type": "http://ns.dasch.swiss/repository#Project",
"http://ns.dasch.swiss/repository#hasStartDate": "2016.07",
"@id": "http://ns.dasch.swiss/beol"
}
```
@@ -129,28 +129,8 @@ otherwise `None`.
## Returning a JSON-LD Response
Each API response is represented by a message class that extends
`KnoraResponseV2`, which has a method `toJsonLDDocument` that specifies
the target ontology schema:
```scala
/**
*
* A trait for Knora API V2 response messages. Any response can be converted into JSON-LD.
*
*/
trait KnoraResponseV2 {
/**
* Converts the response to a data structure that can be used to generate JSON-LD.
*
* @param targetSchema the Knora API schema to be used in the JSON-LD document.
* @return a [[JsonLDDocument]] representing the response.
*/
def toJsonLDDocument(targetSchema: ApiV2Schema, settings: KnoraSettingsImpl, schemaOptions: Set[SchemaOption]): JsonLDDocument
}
```
The implementation of this method constructs a `JsonLDDocument`,
`KnoraJsonLDResponseV2`, which has a method `toJsonLDDocument` that specifies
the target ontology schema. The implementation of this method constructs a `JsonLDDocument`,
in which all object keys are full IRIs (no prefixes are used), but in which
the JSON-LD context also specifies the prefixes that will be used when the
document is returned to the client. The function `JsonLDUtil.makeContext`
@@ -239,6 +219,8 @@ RouteUtilV2.runRdfRouteWithFuture(
## Generating Other RDF Formats
`RouteUtilV2.runRdfRouteWithFuture` implements
[HTTP content negotiation](https://tools.ietf.org/html/rfc7231#section-5.3.2), and converts JSON-LD
responses into [Turtle](https://www.w3.org/TR/turtle/)
or [RDF/XML](https://www.w3.org/TR/rdf-syntax-grammar/) as appropriate.
[HTTP content negotiation](https://tools.ietf.org/html/rfc7231#section-5.3.2). After
determining the client's preferred format, it asks the `KnoraResponseV2` to convert
itself into that format. `KnoraResponseV2` has an abstract `format` method, whose implementations
select the most efficient conversion between the response message's internal
representation (which could be JSON-LD or Turtle) and the requested format.
@@ -419,6 +419,7 @@ class ApplicationActor extends Actor with Stash with LazyLogging with AroundDire
new ValuesRouteV2(routeData).knoraApiPath ~
new StandoffRouteV2(routeData).knoraApiPath ~
new ListsRouteV2(routeData).knoraApiPath ~
new MetadataRouteV2(routeData).knoraApiPath ~
new AuthenticationRouteV2(routeData).knoraApiPath ~
new GroupsRouteADM(routeData).knoraApiPath ~
new ListsRouteADM(routeData).knoraApiPath ~
@@ -171,6 +171,13 @@ case class GravsearchException(message: String) extends RequestRejectedException
*/
case class InvalidJsonLDException(msg: String, cause: Throwable = null) extends RequestRejectedException(msg, cause)

/**
* An exception indication that the RDF submitted to the API v2 was invalid.
*
* @param msg a description of the error.
* @param cause the cause for the error
*/
case class InvalidRdfException(msg: String, cause: Throwable = null) extends RequestRejectedException(msg, cause)

/**
* An abstract class for exceptions indicating that something went wrong and it's not the client's fault.
@@ -26,6 +26,7 @@ scala_library(
"@maven//:com_typesafe_akka_akka_stream_2_12",
"@maven//:com_typesafe_play_twirl_api_2_12",
"@maven//:com_typesafe_scala_logging_scala_logging_2_12",
"@maven//:org_apache_jena_apache_jena_libs",
"@maven//:commons_io_commons_io",
"@maven//:commons_validator_commons_validator",
"@maven//:io_spray_spray_json_2_12",
@@ -2417,6 +2417,16 @@ class StringFormatter private(val maybeSettings: Option[KnoraSettingsImpl] = Non
OntologyConstants.NamedGraphs.DataNamedGraphStart + "/" + project.shortcode + "/" + project.shortname
}

/**
* Given the [[ProjectADM]] calculates the project's metadata named graph.
*
* @param project the project's [[ProjectADM]].
* @return the IRI of the project's metadata named graph.
*/
def projectMetadataNamedGraphV2(project: ProjectADM): IRI = {
OntologyConstants.NamedGraphs.DataNamedGraphStart + "/" + project.shortcode + "/" + project.shortname + "/metadata"
}

/**
* Given the project IRI, checks if it is in a valid format.
*
@@ -420,7 +420,7 @@ case class ProjectADM(id: IRI,
append(logo).
append(ontologies.toSet).
append(status).
append(selfjoin).hashCode()
append(selfjoin).toHashCode
}
}

@@ -270,7 +270,20 @@ case class SparqlExtendedConstructResponse(statements: Map[SubjectV2, SparqlExte
* @param graphIri the IRI of the named graph.
* @param outputFile the destination file.
*/
case class GraphFileRequest(graphIri: IRI, outputFile: File) extends TriplestoreRequest
case class NamedGraphFileRequest(graphIri: IRI, outputFile: File) extends TriplestoreRequest

/**
* Requests a named graph, which will be returned as Turtle. A successful response
* will be a [[NamedGraphDataResponse]].
*
* @param graphIri the IRI of the named graph.
*/
case class NamedGraphDataRequest(graphIri: IRI) extends TriplestoreRequest

/**
* A graph of triples in Turtle format.
*/
case class NamedGraphDataResponse(turtle: String)

/**
* Represents a SPARQL Update operation to be performed.
@@ -284,7 +297,6 @@ case class SparqlUpdateRequest(sparql: String) extends TriplestoreRequest
*/
case class SparqlUpdateResponse()


/**
* Represents a SPARQL ASK query to be sent to the triplestore. A successful response will be a
* [[SparqlAskResponse]].
@@ -336,6 +348,19 @@ case class InsertRepositoryContent(rdfDataObjects: Seq[RdfDataObject]) extends T
*/
case class InsertTriplestoreContentACK()

/**
* Inserts raw RDF data into the repository.
*
* @param graphContent contains graph data as turtle.
* @param graphName the name of the graph.
*/
case class InsertGraphDataContentRequest(graphContent: String, graphName: String) extends TriplestoreRequest

/**
* Sent as a response to [[InsertGraphDataContentRequest]] if the request was processed successfully.
*/
case class InsertGraphDataContentResponse()

/**
* Initialize the repository. This will initiate the (re)creation of the repository and adding data to it.
*

0 comments on commit bf48968

Please sign in to comment.