IriTemplate explained with an example
Note: This article uses term URI and IRI interchangebly, IRIs being genaralized form of URIs supporting Unicode. (For more information see rfc for URI and rfc for IRI)
IRI Templates provide an easy and elegant way to describe a range of IRIs with help of variable expansion. In context of hypermedia driven APIs IRI templates are particularly useful when the server can’t construct a URI by itself; only the client possess the required information to construct desired IRI.
Hydra provides IriTemplate
class which can be used to provide IRI template to smart clients, which can be used
by those clients to construct valid IRIs. As the title of this article suggest we will use an example to explain
working of IriTemplate
in
detail.
Example
{
"@context": "/serverapi/context.jsonld",
"@id": "https://tiles.openplanner.team/planet",
"@type": "Collection",
"search": {
"@type": "IriTemplate",
"template": "https://c.tile.openstreetmap.org/{z}/{x}/{y}.examplejsonld",
"variableRepresentation": "BasicRepresentation",
"mapping": [
{
"@type": "IriTemplateMapping",
"variable": "x",
"property": "tiles:longitudeTile",
"required": true
},
{
"@type": "IriTemplateMapping",
"variable": "y",
"property": "tiles:latitudeTile",
"required": true
},
{
"@type": "IriTemplateMapping",
"variable": "z",
"property": "tiles:zoomTile",
"required": true
}
]
}
}
You can find more details related to this example here
As explained above, in tiled maps when we open a map the client side code uses some formula(the formula may vary according to the tile numbering convention used by the service provider) which uses latitude, longitude and zoom to get tile identifiers(here x and y). When it has value of x and y to identify a tile it makes request to the server for that individual tile.
For example https://c.tile.openstreetmap.org/15/22994/14232.png will return the tile identified by x = 22994 and
y = 14232 with zoom 15.
For x = 22990 and y = 14232 and zoom = 15 the URI will be https://c.tile.openstreetmap.org/15/22990/14232.png,
same way we can construct URIs for different comibnations of X, Y and zoom. To represent such range of URIs we
can use an URI template(IRI template) https://c.tile.openstreetmap.org/{z}/{x}/{y}
.
Such IRI templates can be put in use with help of Hydra IriTemplate
class. It consists of a literal template
and a set of mappings(IriTemplateMapping
). template
holds the IRI template, here https://c.tile.openstreetmap.org/{z}/{x}/{y}.examplejsonld
and IriTemplateMapping
maps varibles in the template
with properties and may specify whether the variable
is required or not.
In the example above variables x, y and z maps to tiles:longiudeTile
, tiles:latitudeTile
and tiles:zoomTile
respectively. And all these variables are specified as required
to expand the IRI template and create a valid IRI.
As the name suggests variableRepresenation
specifies how the IRI template will be expanded and serialized when
values of variables are provided.
As of now it can possibly have one of two values either BasicRepresentation
or ExplicitRepresentation
.
BasicRepresentation
does not differentiate between literals and IRIs, it simple omits data-type and language
information of literals. While ExplicitRepresentation
diffrentiates between literals and IRIs by surrounding
literals with double quotes(“) and it also explicitly specifies language and data-type information of literals,
for more see detailed example.
The client side code might look like this
var client = new HydraClient();
var collection = client.get("/api/planet");
if (colletion.search) {
var filter = {};
for (let mapping of collection.search.mappings) {
filter[mapping.variable] = value of variable; # set value of x, y and z
}
var query = urlTemplate
.parse(collection.search.template)
.expand(filter); # expand the IRI
var data = client.get(query);
for (var member of data.members) {
// do something with the _member_, i.e. display it
}
}
With help of all these a Hydra enabled client can expand the IRI template with provided values of variables. If in
future the URI is changed from https://c.tile.openstreetmap.org/{z}/{x}/{y}
to https://c.tile.openstreetmap.org/{z}/{y}/{x}
the client won’t have any difficulty adjusting to it. Client will receive following kind of response from the server
{
"@context": "/serverapi/context.jsonld",
"@id": "https://tiles.openplanner.team/planet",
"@type": "Collection",
"search": {
"@type": "IriTemplate",
"template": "https://c.tile.openstreetmap.org/{z}/{y}/{x}.examplejsonld",
"variableRepresentation": "BasicRepresentation",
"mapping": [
{
"@type": "IriTemplateMapping",
"variable": "x",
"property": "tiles:longitudeTile",
"required": true
},
{
"@type": "IriTemplateMapping",
"variable": "y",
"property": "tiles:latitudeTile",
"required": true
},
{
"@type": "IriTemplateMapping",
"variable": "z",
"property": "tiles:zoomTile",
"required": true
}
]
}
}
From the reponse data above and the client-side code given above we can see that the client side code won’t require any changes and keep functioning normally. For x = 22990 and y = 14232 and zoom = 15 the URI constucted by the client will be https://c.tile.openstreetmap.org/15/14232/22990.png.
Searching interface supported by hydrus
hydrus utilizes above explained IriTemplate
to provide a searching interface over collection of items.
To every collection response it attaches an IriTempale. This IriTemplate
has template mapping defined for all the properties of the objects contained by the collection.
For illustration the IriTemplate
generated for DroneCollection(defined in our flock-vocab) is attached below.
{
"@type":"IriTemplate",
"mapping":[
{
"@type":"IriTemplateMapping",
"property":"http://auto.schema.org/speed",
"required":false,
"variable":"DroneState[Speed]"
},
{
"@type":"IriTemplateMapping",
"property":"http://schema.org/geo",
"required":false,
"variable":"DroneState[Position]"
},
{
"@type":"IriTemplateMapping",
"property":"http://schema.org/Property",
"required":false,
"variable":"DroneState[Direction]"
},
{
"@type":"IriTemplateMapping",
"property":"http://schema.org/fuelCapacity",
"required":false,
"variable":"DroneState[Battery]"
},
{
"@type":"IriTemplateMapping",
"property":"https://schema.org/status",
"required":false,
"variable":"DroneState[SensorStatus]"
},
{
"@type":"IriTemplateMapping",
"property":"vocab:Drone",
"required":false,
"variable":"DroneState[DroneURI]"
},
{
"@type":"IriTemplateMapping",
"property":"http://schema.org/name",
"required":false,
"variable":"name"
},
{
"@type":"IriTemplateMapping",
"property":"http://schema.org/model",
"required":false,
"variable":"model"
},
{
"@type":"IriTemplateMapping",
"property":"http://auto.schema.org/speed",
"required":false,
"variable":"MaxSpeed"
},
{
"@type":"IriTemplateMapping",
"property":"http://schema.org/device",
"required":false,
"variable":"Sensor"
}],
"template":"/serverapi/DroneCollection(DroneState[Speed], DroneState[Position], DroneState[Direction], DroneState[Battery],
DroneState[SensorStatus], DroneState[DroneURI], name, model, MaxSpeed, Sensor)",
"variableRepresentation":"hydra:BasicRepresentation"
}
hydrus also provides suppport for searching over sub-properties of properties. Variable names of such properties are formed as `
MainProperty[subProperty]. For example to search for all the Drones going in some particular direction, client can use the
DroneState[Direction]` variable.