Hydra and SHACL - Part 2 - IRI Templates
In the previous post I presented the simplest functionality of loading remote form contents by having SHACL property shape reference a Hydra Core collection.
In the second part I will extend that example to create a form with multiple connected dropdowns, where each one is only populated when other(s) have been selected, which is a common scenario seen in (web) applications.
TL;DR; can I see it working?
The screenshot below links to Shaperone Playground which implements the ideas described in the subsequent paragraphs.
Filtering collections with Hydra
In addition to hydra:collection
, the Hydra Core vocabulary comes with another general-purpose property hydra:search
. Unlike most predicates which would link to another resource, identified by a concrete URI, its objects are instances of URI Templates, defined by RFC6570.
For example, let’s have a “State collection” resource which returns country’s first-level administrative division. It would come with a search template so that clients can construct filtered URIs:
The client must provide template values to a Hydra library which will return a URI fit for dereferencing. This is called expansion
by the RFC6570. A Hydra client will take a graph node with values being attached to that node using the hydra:property
as defined by the template and match those property/object pairs to the template variables.
Here’s an example of such a template variable model, where JSON-LD @context
has been constructed from the hydra:mapping
, although the JSON keys may be irrelevant for the expansion if the implementation only relies on the actual graph data.
Combine this with the template above to get
/states?country=http%3A%2F%2Fwww.wikidata.org%2Fentity%2FQ27
Read more about Hydra’s template here
Connecting form fields
The idea is simple:
- A SHACL Shape describes a graph structure
- A form can be generated for agents (usu. humans) to create an instance of such a graph
- Use the created graph to expand a template
Now, a form in such a scenario could simply be used to filter a collection for display, but I propose to short-circuit it back into the form itself so that the filtered collection, when dereferenced, provides values for other fields.
The Person
shape above has two properties. The first will generate a dropdown with a selection of countries as described in the first Hydra+SHACL post. The second, while it’s also going to render a dropdown, will not be populated until a country is selected (hydra:required true
).
The glue here is matching property shared between sh:path
of the upstream field and hydra:property
of the downstream’s search template. In other words, when the form’s graph node receives the value for the schema:addressCountry
predicate, the “states” will be loaded.
Less APIs, more Web Standards!
Again this time, the playground example does not “talk” to an actual API but instead runs SPARQL queries encoded into query string parameters of Wikidata’s query endpoint. The trick is to replace a URI of the variable with a URI Template placeholder. Just gotta make sure that the braces are not percent-encoded.
The query to load states is simple:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Loading cities is slightly more complicated, accounting for deeper graphs where a state is the root and also various types of cities recognised by Wikidata.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Tried as I might, the cities query does not work for every country. United States, Germany and Poland are fine. On the other hand, for Colombia and Australia it finds no cities at all. Queries for Australian cities are also surprisingly slow…
It is not important for the example, but I would be curious to learn from a Wikidata expert how it can be improved.