Three v2 APIs answer "things near here", and each has its own idea of what that means. I ran into it implementing a Track API provider (#2995) next to an existing History provider.
| API |
Spatial parameters |
Shape |
Format |
| Resources |
bbox; distance + position |
rectangle; square around a point |
bbox=lon1,lat1,lon2,lat2 (lower-left, upper-right); distance in metres from the vessel, or from position=lon,lat |
| History |
none |
— |
The route rebuilds the provider request from a fixed field list, so a bbox or radius in the query is dropped silently and the client gets an unfiltered 200 |
| Tracks (#2995) |
bbox |
rectangle |
bbox=west,south,east,north |
Three things fall out of that:
- Tracks reused half of Resources and stopped. Its
bbox is Resources' bbox: the same four numbers in the same order, only described as compass edges instead of corner pairs, so a client cannot tell from the docs that it already knows this parameter. It did not take the centre-plus-distance half, so "who passed within N metres of this waypoint" cannot be asked of the Track API at all.
distance is a square. The one centre-and-distance filter in the server returns a square whose edges are distance metres from the centre. A resource on the diagonal at 1.4× the distance still matches. Nobody reading distance=2000 expects that.
- History has nothing, and cannot be extended from below. signalk-parquet's own routes have carried
bbox and a true-circle radius=lon,lat,metres for a while, with correlation for non-position paths ("depth while I was inside this area"). On the v2 route that is unreachable, because the server owns the parser and discards what it does not know. A provider cannot add a spatial filter to v2 History no matter what it implements.
Each API is choosing on its own, which is how we got here.
Proposal
One spatial parameter set, defined once and used by every v2 API that filters by location. Three shapes, each with an unambiguous name:
bbox=west,south,east,north, GeoJSON order, documented the same way everywhere. Resources keeps accepting its current corner-pair form, which is numerically identical.
position=lon,lat + circle=<metres>: a circle. Great-circle or spheroid distance, and the spec should say which.
position=lon,lat + square=<metres>: a square whose edges are that many metres from the centre. This is what Resources' distance does today, so it keeps working: distance becomes a legacy alias of square in Resources, documented as such, and is not introduced anywhere else.
position defaults to the vessel's own position, as it does in Resources now.
History and Tracks both accept the set. For History, the semantics signalk-parquet already implements on its own routes are a reasonable starting point: position paths are filtered directly, other paths are filtered to the times the vessel was inside the area.
Routes that own their parser should reject an unknown query parameter with a 400, or at least echo what they applied, rather than silently returning unfiltered data.
Happy to draft the History side, since the provider implementation and tests exist, and to align the Track provider once the shape is agreed. Related: #2995, #2504.
Three v2 APIs answer "things near here", and each has its own idea of what that means. I ran into it implementing a Track API provider (#2995) next to an existing History provider.
bbox;distance+positionbbox=lon1,lat1,lon2,lat2(lower-left, upper-right);distancein metres from the vessel, or fromposition=lon,latbboxorradiusin the query is dropped silently and the client gets an unfiltered 200bboxbbox=west,south,east,northThree things fall out of that:
bboxis Resources'bbox: the same four numbers in the same order, only described as compass edges instead of corner pairs, so a client cannot tell from the docs that it already knows this parameter. It did not take the centre-plus-distance half, so "who passed within N metres of this waypoint" cannot be asked of the Track API at all.distanceis a square. The one centre-and-distance filter in the server returns a square whose edges aredistancemetres from the centre. A resource on the diagonal at 1.4× the distance still matches. Nobody readingdistance=2000expects that.bboxand a true-circleradius=lon,lat,metresfor a while, with correlation for non-position paths ("depth while I was inside this area"). On the v2 route that is unreachable, because the server owns the parser and discards what it does not know. A provider cannot add a spatial filter to v2 History no matter what it implements.Each API is choosing on its own, which is how we got here.
Proposal
One spatial parameter set, defined once and used by every v2 API that filters by location. Three shapes, each with an unambiguous name:
bbox=west,south,east,north, GeoJSON order, documented the same way everywhere. Resources keeps accepting its current corner-pair form, which is numerically identical.position=lon,lat+circle=<metres>: a circle. Great-circle or spheroid distance, and the spec should say which.position=lon,lat+square=<metres>: a square whose edges are that many metres from the centre. This is what Resources'distancedoes today, so it keeps working:distancebecomes a legacy alias ofsquarein Resources, documented as such, and is not introduced anywhere else.positiondefaults to the vessel's own position, as it does in Resources now.History and Tracks both accept the set. For History, the semantics signalk-parquet already implements on its own routes are a reasonable starting point: position paths are filtered directly, other paths are filtered to the times the vessel was inside the area.
Routes that own their parser should reject an unknown query parameter with a 400, or at least echo what they applied, rather than silently returning unfiltered data.
Happy to draft the History side, since the provider implementation and tests exist, and to align the Track provider once the shape is agreed. Related: #2995, #2504.