Closed hyprdia closed 1 year ago
First of all - I'd split it into several operations each expecting different class. Your example:
"expects": [
"http://api.example.com/classes/Folder",
"http://api.example.com/classes/File",
]
would imply a resource that is both Folder
and File
is expected which I believe is far from your requirements.
As for additional constraints on those expectations i see three solutions:
Both may put additional stress on the client, but the former feels better for this purpose. Both constructs may be invisible for generic clients understanding pure hydra, yet still the client may be instructed that the server uses extensions via extension
property attached to ApiDocumentation
You could also consider typeahead-like or list of possible values in order to constrain user from providing any kind of details.
The supportedClass
/supportedProperty
and search
might come in handy. There are some examples in the release-candidate spec sitting in this PR
Hydra schema defines the expects field as a Link
The hydra:expects
is a predicate declared as link so the client can see a notion that the operation is somehow linked to the resource in expects
relation, but the predicate can be used in between whatever is in the domainIncludes
(left part of the relation) and rangeIncludes
(right part of the relation), i.e.:
some:Operation hydra:expects some:Resource
would imply a resource that is both Folder and File is expected which I believe is far from your requirements.
The goal here was to interact with multiple resources in one request. This was not to be interpreted the same as JSON-LD@type
:
{
"@type": [
"http://api.example.com/classes/Folder",
"http://api.example.com/classes/File",
]
}
The question was the result of certain incomprehensions of the REST architecture style from my part, and basically, it seems that Hydra enforces it in a way by using the expects
to link to one resource, which, in retrospect, is a good safeguard for mistakes from people new to REST.
First of all - I'd split it into several operations each expecting different class. Your example:
I closed the question because I am in the process of developing another way to do this using the expects
. The best design to achieve my purpose is still pending, but one of the solutions involves changing the state of a resource e.g. a Folder
from draft
to complete
. This would imply a PATCH
sent to only modify one field of a resource. Maybe I miss something but I cannot see any way to describe this operation. The expects
seems to allow to describe a full Resource
, same as your answer:
some:Operation hydra:expects some:Resource
Let's say my resource is the following:
{
"@context": {
...
},
"@id": "folders/tgbF5312Kwnb9fdsteDhG6",
"@type": "classes:Folder",
"createdAt": "2008-10-31T15:07:38.6875000-05:00",
"state": "draft",
"operation": [
{
"title": "Change the folder state to `complete`",
"method": "PATCH",
"expects": ????
...
}
]
}
how would we describe the PATCH to only change the state of the Folder
?
As for using SHACL, I indeed intend to use it, Integrations exist with client libraries that allows to use SHACL to generate forms from it. I still need to use them and make sure they do what I need but at least I have something to start with if I need something not provided already. Thanks for pointing out these possible solutions.
I decided to go with json schema in my expectations using the JSON Schema in RDF which describes JSON schema in RDF and allows to use a tool like JSON Forms or any other tool that supports json schemas which are plentiful compared SHACL.
Since expects
covers anything that be described using rdfs
:
{
"@id": "hydra:expects",
"@type": "hydra:Link",
"label": "expects",
"comment": "The information expected by the Web API.",
"domainIncludes": ["hydra:Operation", "hydra:RetractedOperationSpecification"],
"rangeIncludes": ["rdfs:Resource", "hydra:Resource", "rdfs:Class", "hydra:Class"],
"isDefinedBy": "http://www.w3.org/ns/hydra/core",
"vs:term_status": "testing"
}
we can use Json schema RDF description to define the value of expects
.
{
"@context": {
"jsonschema": "https://www.w3.org/2019/wot/json-schema"
...
},
"@id": "folders/tgbF5312Kwnb9fdsteDhG6",
"@type": "classes:Folder",
"createdAt": "2008-10-31T15:07:38.6875000-05:00",
"state": "draft",
"operation": [
{
"title": "Change the folder state to `complete`",
"method": "PATCH",
"name": "folder:change-state",
"expects": {
"jsonschema:type": "object",
"jsonschema:properties": {
"jsonschema:oneOfEnum": {
"jsonschema:type": "string",
"jsonschema:oneOf": [
{
"jsonschema:const": "complete"
},
{
"jsonschema:const": "other-state"
}
]
}
}
]
}
The requirements here would be to inform the client that I use a jsonschema extension.
Describe your API requirement
I need to be able to create multiple resources types in one HTTP POST for which a particular endpoint has been defined. We could make an analogy with a file system. Let’s say I have two kinds of resources: folders and files: I would like to be able to tell the client that I expect a list folders and files under a particular folder.
For example, with the endpoint
http://api.example.com/folders/
, which contains all resources of typeFolder
, I have defined a sub resourcetree
e.g.http://api.example.com/folders/folderId/tree
which would allow to POST folders and files to be created under a specific folder instance.Now, I would like to be able to describe the operation in
Hydra
using something like this:which would simply list all requested files and folders to be able to create a file structure. In my particular scenario the user would need to provide a specific files structure known and provided by the API, we could imagine creating a Maven project with a predefined folders structure or something similar. The point of passing all this information is to be able, from the client perspective, to present everything the user needs to create in any way it wants, it could be a form with multiple sub-sections, or a wizard which would present all the information the user needs to provide once at a time.
What would be even better, is if I would be able to use SHACL to define all the requirements for form display, like here:
This is a toy example with no real meaning but I think it describes the essential: I need to pass a list of different resources types to an endpoint to create multiple resources in one POST request.
Solution(s)
I considered defining a custom
rdf:Class
/sh:NodeShape
that would list all the required resources needed and just be pointed at by the operationexpects
field. This would work but, this is not really elegant as the hypermedia message should in my opinion be responsible for carrying this kind of information, not RDF. Also, this is not a class that would be valid for all folders, to continue the directory example: each directory would need to define it's own particular class since the requirements can change from folder to folder.I considered a SHACL blank node to describe what to expect a bit like in this answer from @tpluscode but the problem, maybe I miss something, is that the Hydra schema defines the
expects
field as aLink
:In fact, it seems to me that an Hydra API expects the client to send a second request in order to know the value of the parameters for an operation. If this is the case, I also would like to know what motivates this choice in the first place.
Thanks for your assistance,
Sébastien Hamel
P.S. Also, the Hydra Console does not seem to work at the moment, any plan to put it back online?