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(api-v2): Control JSON-LD nesting via an HTTP header (DSP-1084) #1758

Merged
merged 5 commits into from Nov 18, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/03-apis/api-v2/introduction.md
Expand Up @@ -74,6 +74,18 @@ set of RDF triples, an equivalent JSON-LD response can explicitly
provide data in a hierarchical structure, with objects nested inside
other objects.

### Hierarchical vs. Flat JSON-LD

The client can choose between hierarchical and flat JSON-LD. In hierarchical
JSON-LD, entities with IRIs are inlined (nested) where they are used. If the
same entity is used in more than one place, it is inlined only once, and other
uses just refer to its IRI. In Knora's flat JSON-LD, all entities with IRIs are located
at the top level of the document (in a `@graph` if there is more than one of them).
This setting does not affect blank nodes, which are always inlined (unlike in standard
flat JSON-LD). Knora ontologies are always returned in the `flat` rendering; other kinds
of responses default to `hierarchical`. To use this setting, submit the HTTP header
`X-Knora-JSON-LD-Rendering` with the value `hierarchical` or `flat`.

## Knora IRIs

Resources and entities are identified by IRIs. The format of these IRIs
Expand Down
389 changes: 389 additions & 0 deletions test_data/metadataE2EV2/metadata-flat.jsonld

Large diffs are not rendered by default.

394 changes: 394 additions & 0 deletions test_data/metadataE2EV2/metadata.ttl

Large diffs are not rendered by default.

28 changes: 28 additions & 0 deletions webapi/src/main/scala/org/knora/webapi/OntologySchema.scala
Expand Up @@ -72,6 +72,23 @@ case object MarkupAsStandoff extends MarkupRendering
*/
case object NoMarkup extends MarkupRendering

/**
* A trait representing options that affect the format of JSON-LD responses.
*/
sealed trait JsonLDRendering extends SchemaOption

/**
* Indicates that flat JSON-LD should be returned, i.e. objects with IRIs should be referenced by IRI
* rather than nested. Blank nodes will still be nested in any case.
*/
case object FlatJsonLD extends JsonLDRendering

/**
* Indicates that hierarchical JSON-LD should be returned, i.e. objects with IRIs should be nested when
* possible, rather than referenced by IRI.
*/
case object HierarchicalJsonLD extends JsonLDRendering

/**
* Utility functions for working with schema options.
*/
Expand Down Expand Up @@ -118,4 +135,15 @@ object SchemaOptions {
def renderMarkupAsStandoff(targetSchema: ApiV2Schema, schemaOptions: Set[SchemaOption]): Boolean = {
targetSchema == ApiV2Complex && schemaOptions.contains(MarkupAsStandoff)
}

/**
* Determines whether flat JSON-LD should be returned, i.e. objects with IRIs should be referenced by IRI
* rather than nested.
*
* @param schemaOptions the schema options submitted with the request.
* @return `true` if flat JSON-LD should be returned.
*/
def returnFlatJsonLD(schemaOptions: Set[SchemaOption]): Boolean = {
schemaOptions.contains(FlatJsonLD)
}
}
Expand Up @@ -32,7 +32,7 @@ import spray.json.{JsNumber, JsObject, JsString, JsValue}

/**
* The Knora exception handler is used by akka-http to convert any exceptions thrown during route processing
* into HttpResponses. It is brought implicitly into scope at the top level [[KnoraLiveService]].
* into HttpResponses. It is brought implicitly into scope by the application actor.
*/
object KnoraExceptionHandler extends LazyLogging {

Expand Down Expand Up @@ -156,7 +156,7 @@ object KnoraExceptionHandler extends LazyLogging {
// ... and the HTTP status code.
HttpResponse(
status = httpStatus,
entity = HttpEntity(ContentType(MediaTypes.`application/json`), jsonLDDocument.toCompactString)
entity = HttpEntity(ContentType(MediaTypes.`application/json`), jsonLDDocument.toCompactString(false))
)
}

Expand Down