De laatste tijd komen er verschillende vragen over het verkeerd gebruik of ontbreken van GeoJSON in REST API’s die bij Kadaster/PDOK en DSO aangeboden worden. We willen geen WFS nabouwen (daar is immers WFS voor uitgevonden), maar omdat de API’s andere ingangen bieden en bovendien niet elke API ook als WFS wordt aangeboden, lijkt het óók aanbieden van een application/geo+json
response (en dus gebaseerd op features) mij een welkome aanvulling voor deze REST API’s. Dit kan eenvoudig middels content negotiation, echter heb ik dan wel een aantal vragen voor de GIS mensen onder ons over hoe we een aantal features zouden kunnen doorvertalen.
Hoe gaan we om met resources die helemaal geen geometrieën hebben?
Neem bijvoorbeeld de /nummeraanduidingen
van de BAG. Een nummeraanduiding heeft zelf geen geometrie. Ziet deze er dan ongeveer uit zoals hieronder?
{
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"id": 1,
"titel": "item 1"
}
}, {
"type": "Feature",
"properties": {
"id": 2,
"titel": "item 2"
}
}
}
En is het dan zinvol om hier überhaupt een GeoJSON response voor aan te bieden? Ik weet niet wat GIS clients hiermee doen, maar we kunnen er natuurlijk ook voor kiezen om het verzoek voor application/geo+json
alleen te accepteren als er ook geometrieën in het spel zijn.
Hoe gaan we om met resources die meerdere geometrieën hebben?
Neem bijvoorbeeld de /wegdelen
van het Nationaal Wegenbestand. Eén wegdeel heeft zowel een vlakGeometrie
als een lijnGeometrie
. Beiden zijn properties van dezelfde resource. GeoJSON ondersteunt naar mijn weten maar één geometrie per Feature
; een FeatureCollection
heeft zelf weer geen properties. Bijvoorbeeld het fictieve wegdeel /wegdelen/123
in application/json
:
{
"id": 123,
"titel": "Wegdeel 123",
"vlakGeometrie": {
"type": "Point", //zal in de praktijk nooit een Point zijn maar dat terzijde ;)
"coordinates": [0.0, 0.0]
},
"puntGeometrie": {
"type": "Point",
"coordinates": [0.0, 0.0]
},
}
In GeoJSON zul je dan denk ik zoiets moeten krijgen:
{
"type": "FeatureCollection",
"properties": { //mag niet, zie uitleg hieronder
"id": 123,
"titel": "Wegdeel 123"
},
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [0.0, 0.0]
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [0.0, 0.0]
}
}
]
}
Bovenstaande is echter geen oplossing, want dan loop je tegen de volgende problemen aan:
- een
FeatureCollection
kent geenproperties
in GeoJSON. -
vlakGeometrie
enpuntGeometrie
zijn niet van elkaar te onderscheiden (je weet niet welkeFeature
welke van de 2 uitdrukt. - een
FeatureCollection
mag geen onderdeel zijn van een andereFeatureCollection
. Hiermee wordt het uitdrukken van een lijst met resources (in dit geval zou dat/wegdelen
zijn) die meerdere geometrieën hebben onmogelijk.
Navigatie in GeoJSON
Momenteel bieden we enkel HAL (application/hal+json
) responses aan in onze API’s. Een van de belangrijkste redenen is dat dit het mogelijk maakt om naar gerelateerde resources elders in de API te kunnen navigeren. Veelgebruikte zogenaamde ‘hypermedia controls’ zijn de _links.next
en _links.prev
objecten om door gepagineerde collecties te kunnen navigeren. Een ander voorbeeld is om met de BAG API van een nummeraanduiding
naar een adresseerbaarObject
te kunnen navigeren. GeoJSON kent hier niets voor, en het toevoegen van een _links
object a la HAL zou invalid GeoJSON opleveren. De makkelijkste optie is om de hypermedia controls in de response headers mee te geven, dan krijg je dus zoiets in application/hal+json
:
//application/hal+json
{
"_embedded": {
"items": [{
"id": 1,
"titel": "item 1",
"_links": {
"self": {
"href": "https://.../items/1"
}
}
}, {
"id": 2,
"titel": "item 2",
"_links": {
"self": {
"href": "https://.../items/2"
}
}
}]
}
"_links": {
"next": {
"href": "https://.../items?page=3"
},
"prev": {
"href": "https://.../items?page=1"
}
}
}
En zoiets in application/geo+json
:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"id": 1,
"titel": "item 1"
}
}, {
"type": "Feature",
"properties": {
"id": 2,
"titel": "item 2"
}
}
]
}
Met de Link
response header krijg je dan Link: <https://.../items?page=3>; rel="next", <https://.../items?page=1>; rel="prev"
, echter moet je dan eigenlijk voor alle individuele resources ook relaties verzinnen en deze opnemen in de Link
header: Link: <https://.../items?page=3>; rel="next", <https://.../items?page=1>; rel="prev", <https://.../items/1>; rel="items/1.self", <https://.../items/2>; rel="items/2.self"
.
Overigens is het laatstgenoemde een probleem dat ook speelt voor andere formaten die geen eigen hypermedia mechanisme hebben zoals plain JSON, maar die bieden we momenteel dan ook helemaal nog niet aan
Ik hoor graag jullie input/thoughts zodat we hier wellicht een welkome feature request (ook voor de DSO API Strategie) uit kunnen halen. Alvast bedankt voor het meedenken!