Openactive Session Exchange Standard v0.1 (draft)
This document represents a minimal early draft of a standard for data exchange for physical activity data. It is highly likely to change completely between now and the first published version, so this document should only be used to guide swift implementations where the quick win of data sharing and shared learning are high priorities.
This standard is tightly defined to cover data exchange itself.
Goals:
Non-Goals:
The most basic implementation of this standard, which requires polling.
A real-time, high volume alternative to the basic implementation.
A single REST endpoint that returns a JSON page of results given two query parameters:
The data returned can be defined as follows:
var query;
if (queryParams.from) {
query = Session.query().filter((Session.modified == queryParams.from && Session.id > queryParams.after) || (Session.modified > queryParams.from));
} else {
query = Session.query()
}
return query.sort([Session.modified, Session.id])
The above can be run for each relevant entity type (e.g. club, courses, sessions), with separate endpoints for each.
Note that deleted items are included in the response with a deleted state, but no <data> associated.
Response grammar / example:
<response> => {
items: [<item>,<item>,<item>,...],
next: '/getAfterTimestamp?from=<date>&after=<id>'
}
<item> => {
state: 'Updated' | 'Deleted',
kind: "session",
id: "{21EC2020-3AEA-4069-A2DD-08002B303123}",
modified: Date(a),
data: <data>
}
<data> => {
lat: 51.5072,
lng: -0.1275,
name: 'Acrobatics with Dave',
groupId: "{0657FD6D-A4AB-43C4-84E5-0933C84B4F4F}"
clubId: "{38A52BE4-9352-453E-AF97-5C3B448652F0}"
}
A full example response:
/getSessionsAfterTimestamp?from=Date(a)
-> { items: [{
state: 'Updated',
kind: “session”,
id: “{c15814e5-8931-470c-8a16-ef45afedaece}”,
modified: Date(a),
data: {
lat: 51.5072,
lng: -0.1275,
name: 'Acrobatics with Dave',
clubId: "{fc1f0f87-0538-4b05-96a0-cee88b9c3377}"
}roast
},{
state: 'Deleted',
kind: “session”,
id: “{d97f73fb-4718-48ee-a6a9-9c7d717ebd85}”,
modified: Date(b)
}],
next: '/getSessionsAfterTimestamp?from=Date(b)&after={d97f73fb-4718-48ee-a6a9-9c7d717ebd85}'
}
This paging allows ongoing data synchronisation to synchronize all data, that can be replayed arbitrarily by the client.
There are a variety of technologies that should allow us to stream data instead of polling, allowing near-real-time updates for high volume/load scenarios. This is worth considering in the second iteration of the standard, so the below are a collection of ideas of how this could be implemented.
https://en.wikipedia.org/wiki/Advanced_Message_Queuing_Protocol
RabbitMQ et. al. would provide a two way channel for events, but we’d need to think about certificates etc. as it’s not as simple as HTTPS.
It’s potentially much more simple to use Server-Sent Events (over HTTP) (https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)
Example session:
/stream?from=Date(a)
->
event: create
data: {"id": 1, "timestamp": Date(a), "data": {"name": "Juniors' Netball", "lat": 51.5072, "lng": -0.1275}}
event: create
data: {"id": 2, "timestamp": Date(a), "data": {"name": "Afternoon Rounders", "lat": 51.5072, "lng": -0.1275}}
/stream?from=Date(a)&after=2
->
event: create
data: {"id": 3, "timestamp": Date(a), "data": {"name": "Adults' British Bulldog", "lat": 51.5072, "lng": -0.1275}}
event: update
data: {"id": 1, "timestamp": Date(b), "data": {"lat": 51.51, "lng": -0.1266}}
/stream?from=Date(b)&after=1
->
event: create
data: {"id": 4, "timestamp": Date(b), "data": {"name": "Seniors Disco Cycling", "lat": 51.5072, "lng": -0.1275}}
event: delete
data: {"id": 2, "timestamp": Date(c)}
(Date(c) > Date(b) > Date(a))
Version 0.1
This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License.
To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/