Describe the requirement
We've approached the problem of non-RDF media types a few times already. Unfortunately it seems that each time it was not focused enough. Either mixed with collections (#187) or lacking broader context (#186).
Looking back at both, I think they are on track, but need a little more refinement.
For this issues, I'd like to focus on expects only and not returned representations
Hydra-agnostic example
I would distinguish 3 kinds of requests coming to a Hydra API:
-
RDF payloads - such that are currently described by expects and Class.
-
Non RDF-payloads
Directly uploading an image instead of RDF:
POST /movie/123/poster-image HTTP/2
Content-Type: image/png
...File bytes...
-
multipart/form-data
Submitting multiple images and RDF data:
PUT /movie/123/image-gallery HTTP/2
Content-Type: multipart/form-data; boundary=----hydra-content
----hydra-content
Content-Disposition: form-data; filename="poster.png"
Content-Type: image/png
...Poster image...
----hydra-content
Content-Disposition: form-data; filename="cast.jpeg"
Content-Type: image/jpeg
...Image of actors...
----hydra-content
Content-Type: application/ld+json
{
"@type": "mov:Gallery",
"description": {
"@value": "Pictures for movie /movie/123"
}
}
----hydra-content
Hydra should allow describing operations which expect both kinds of file uploads.
Proposed solutions
It is important to keep support for the current expect semantics.
I propose that we extend the existing structure with a media-type description. Unfortunately it is not possible to have it both ways without revolutionising the structure, so the vocab will have to remove rdfs:range from expects and use schema:rangeIncludes instead.
{
"@id": "hydra:expects",
- "range": "hydra:Class",
+ "schema:rangeIncludes": [
+ "hydra:Class",
+ "hydra:RequestSpecification"
+ ]
},
Example of hydra:Class usage
{
"@type": "Operation",
"expects": {
"@type": "RequestSpecification",
"content": {
"@type": "SupportedClassContent",
"class": "mov:Movie"
}
}
}
This would be equivalent to "expects": "mov:Movie" and both should be supported at least for a while.
Example of non-RDF payload
{
"@type": "Operation",
"expects": {
"@type": "RequestSpecification",
"content": {
"@type": "RawContent",
"supportedContentType": [ "image/png", "image/jpeg" ]
}
}
}
supportedContentType could also use a more elaborate structure though I'm not conviced it's necessary.
Example of multipart
{
"@type": "Operation",
"expects": {
"@type": "RequestSpecification",
"content": {
"@type": "MultipartContent",
"allowedParts": [
{
"supportedContentType": [ "image/png", "image/jpeg" ],
"maxCount": 2
},
{
"@type": "SupportedClassContent",
"class": "mov:Movie",
"minCount": 1,
"maxCount": 1
}
]
}
}
}
Above interpreted as:
- allowing 0-2 image parts
- requiring one RDF-part with
mov:Movie
allowedParts has same domain as content, extended with multipart-specific bit such as the min/max count
MultipartContent would have to become part of the core vocabulary.
Implications
The consequences of such design are far reaching:
-
By introducing RequestSpecification we can directly describe HTTP requests (such as by using expectHeader)
-
The content predicat can be an extension point we've talked about, allowing 3rd party vocab to describe bodies using SHACL. Something like
ShaclContentSpecification subclassOf ContentSpecification
-
It will even be possible to define operations which expect markdown, plain text or any other textual format
Alternative solutions
Here's how Open API does that for file uploads and multipart requests. For example
requestBody:
content:
multipart/form-data: # Media type
schema: # Request payload
type: object
properties: # Request parts
id: # Part 1 (string value)
type: string
format: uuid
address: # Part2 (object)
type: object
properties:
street:
type: string
city:
type: string
profileImage: # Part 3 (an image)
type: string
format: binary
Note that id , address and profileImage will be separate request parts.
Describe the requirement
We've approached the problem of non-RDF media types a few times already. Unfortunately it seems that each time it was not focused enough. Either mixed with collections (#187) or lacking broader context (#186).
Looking back at both, I think they are on track, but need a little more refinement.
For this issues, I'd like to focus on
expectsonly and not returned representationsHydra-agnostic example
I would distinguish 3 kinds of requests coming to a Hydra API:
RDF payloads - such that are currently described by
expectsandClass.Non RDF-payloads
Directly uploading an image instead of RDF:
multipart/form-dataSubmitting multiple images and RDF data:
Hydra should allow describing operations which
expectboth kinds of file uploads.Proposed solutions
It is important to keep support for the current
expectsemantics.I propose that we extend the existing structure with a media-type description. Unfortunately it is not possible to have it both ways without revolutionising the structure, so the vocab will have to remove
rdfs:rangefromexpectsand useschema:rangeIncludesinstead.{ "@id": "hydra:expects", - "range": "hydra:Class", + "schema:rangeIncludes": [ + "hydra:Class", + "hydra:RequestSpecification" + ] },Example of
hydra:Classusage{ "@type": "Operation", "expects": { "@type": "RequestSpecification", "content": { "@type": "SupportedClassContent", "class": "mov:Movie" } } }This would be equivalent to
"expects": "mov:Movie"and both should be supported at least for a while.Example of non-RDF payload
{ "@type": "Operation", "expects": { "@type": "RequestSpecification", "content": { "@type": "RawContent", "supportedContentType": [ "image/png", "image/jpeg" ] } } }supportedContentTypecould also use a more elaborate structure though I'm not conviced it's necessary.Example of multipart
{ "@type": "Operation", "expects": { "@type": "RequestSpecification", "content": { "@type": "MultipartContent", "allowedParts": [ { "supportedContentType": [ "image/png", "image/jpeg" ], "maxCount": 2 }, { "@type": "SupportedClassContent", "class": "mov:Movie", "minCount": 1, "maxCount": 1 } ] } } }Above interpreted as:
mov:MovieallowedPartshas same domain ascontent, extended with multipart-specific bit such as the min/max countMultipartContentwould have to become part of the core vocabulary.Implications
The consequences of such design are far reaching:
By introducing
RequestSpecificationwe can directly describe HTTP requests (such as by usingexpectHeader)The
contentpredicat can be an extension point we've talked about, allowing 3rd party vocab to describe bodies using SHACL. Something like
ShaclContentSpecification subclassOf ContentSpecificationIt will even be possible to define operations which expect markdown, plain text or any other textual format
Alternative solutions
Here's how Open API does that for file uploads and multipart requests. For example
Note that
id,addressandprofileImagewill be separate request parts.