Skip to content

SOS SPS REST

Alex Robin edited this page Nov 13, 2018 · 24 revisions

REST Bindings for SOS/SPS

Requirements

SOS needs to expose the following resources:

  • Service Capabilities (service info, offerings?)
  • Procedures/Offerings
  • Procedure Descriptions (history)
  • Features of Interest (GeoJSON w/ CRS)
  • Observations
  • Data Streams

In addition, SPS needs to expose:

  • Tasks and their status
  • Control Streams

URLs

The following URL hierarchy can be used to access SOS resources in a REST fashion:

Root is http://domain/endpoint/v2

URL Resource Type Filtering
/ Service Info
/procedures Procedure[] uid, text, geo, creation time, data time, obsprop, procgroup
/procedures/{id} Procedure
/descriptionHistory (desc) AbstractProcess[] as SML-JSON time
/descriptionHistory/latest AbstractProcess as SML-JSON
/descriptionHistory/{idx*} AbstractProcess as SML-JSON
/featuresOfInterest (fois) Feature[] as GeoJSON geo, data time, obsprop
/featuresOfInterest/latest Feature[] as GeoJSON geo, obsprop
/featuresOfInterest/{id} Feature as GeoJSON
/observations (obs) Observation[] as OM-JSON time, foi, obsprop, geo
/observations/{id} Observation as OM-JSON
/observations/latest Observation as OM-JSON
/dataStreams (streams) DataStream[] as SWE-JSON
/dataStreams/{id**} DataStream as SWE-JSON
/dataStreams/{id}/past SWE Record[] (csv, json or binary) time, foi, obsprop, geo
/dataStreams/{id}/latest SWE Record (csv, json or binary) foi, obsprop, geo
/dataStreams/{id}/live SWE Record[] (csv, json or binary) foi, obsprop, geo
For Tasking
/taskingInputs DataStream[] as SWE-JSON
/taskingInputs/{id} DataStream as SWE-JSON
/taskingInputs/{id}/live POST SWE Record as json
/tasks Task[] time
/tasks/{id} Task
/tasks/{id}/status TaskStatus
/featuresOfInterest (fois) Feature[] as GeoJSON uid, text, type, geo, creation time, data time, proc, obsprop
/featuresOfInterest/{id} Feature as GeoJSON
/observations (obs) Observation[] as OM-JSON time, proc, foi, obsprop, geo
/observations/{id} Observation as OM-JSON

(*) idx is 0 for latest, and increment as we're going back in time

(**) reserved data stream names: 'location', 'status'

Paging

Paging and counting is allowed on all collections (i.e. procedures, descriptionHistory, fois, observations, records). Paging can be controlled by client using pageSize and pageToken query args, but the server can also impose a limit on the page size.

Counting Example: http://endpoint/observations/count?time=2017-01-01/2017-02-01

Resources

Service Info

{
  "title": "service title",
  "abstract": "service abstract",
  "keywords": [],
  "serviceType": "SOS",
  "version": "2.0.0",
  "profiles": [],
  "fees": "",
  "accessConstraints": "",
  "provider": {
    "name": "company name",
    "contactInfo": {
      "individualName": "Bob Jones",
      "address": {
        ...
      }
    }
  },
  "creationTime": "2017-01-01T12:30:00Z",
  "lastModified": "2017-01-01T12:30:00Z",
  "links": {
    "self": "http://.../",
    "procedures": "http://.../procedures",
    "featuresOfInterest": "http://.../fois",
    "observations": "http://.../obs"
  }
}

Procedure

{
  "id": "unique integer id assigned by server",
  "uid": "urn:org:sensor:001",
  "name": "Temp Network",
  "description": "Network of air temperature sensors deployed across the city",
  "type": "device/device group/processing/processing group",
  "tags": [],
  "observableProperties": [],
  "observedArea": {
    "type": "Polygon",
    "coordinates": [[
      [100.0, 0.0],
      [101.0, 0.0],
      [101.0, 1.0],
      [100.0, 0.0]
    ]]
  },
  "observationTypes": [],
  "creationTime": "2017-01-01T12:30:00Z",
  "lastModified": "2017-01-01T12:30:00Z",
  "links": {
    "self": "http://.../procedures/56",
    "descriptionHistory": "http://.../procedures/56/desc",
    "featuresOfInterest": "http://.../procedures/56/fois",
    "observations": "http://.../procedures/56/obs",
    "dataStreams": "http://.../procedures/56/streams"
  }
}

AbstractProcess

A SML-JSON SimpleProcess, AggregateProcess, PhysicalComponent or PhysicalSystem object

Feature

A GeoJSON Feature object

{
  "type": "Feature",
  "geometry": {
    "type": "Point",
    "coordinates": [102.0, 0.5]
  },
  "properties": {
    "prop0": "value0"
  },
  "creationTime": "2017-01-01T12:30:00Z",
  "lastModified": "2017-01-01T12:30:00Z"
}

DataStream

{
  "numId": "1",
  "name": "weather",
  "components": {
    "type": "DataRecord",
    ...
  },
  "encodings": [
    "text/csv",
    "application/json"
  ]
}

Task

{
  "numId": "1",
  "creationTime": "2017-01-01T12:30:00Z",
  "lastModified": "2017-01-01T12:30:00Z",
  "status": {
    "estimatedToC": "2017-04-23T12:23:12Z",
    "lastEvent": "",
    "percentCompletion": "50",
    "procedure": "urn:sensor:0001",
    "requestStatus": "ACCEPTED",
    "statusMessage": "no problem so far",
    "taskStatus": "IN-PROGRESS",
    "updateTime": "2017-04-22T12:00:00Z",
    "taskingInput": "input id",
    "taskingParameters": {
      "pan": 12.5,
      "tilt": -15.6 
    }
  }
}

Transactions

New resources are created with a POST request on the parent collection, and updated with PUT or PATCH.

Resources are deleted with a DELETE request using the ID or a filter on the collection

Filtering

Follow OData or OpenSearch convention?

Spatial Filter

fois?bbox=lat,lon,lat,lon

Temporal Filter

streams/weather/historical?time=iso/iso streams/weather/realtime

Websocket extension

Live Data

Websocket connections can be made on */dataStreams/{id}/live URLs with the same filter as regular HTTP connections. (In the core, only HTTP streaming connections are possible on live stream URLs).

Historical Data

The replay extension allows HTTP streaming and websocket connections on */streams/{id}/past URLs to replay data at a particular speed.

Commands

Websocket connections can also be used for tasking by connecting to */commandInputs/{id}/live URLs with an authorized task/session ID. Websocket allows for text/csv and binary encoded tasking messages.

Events

Websocket connections are also possible on collections to get notified of additions/deletions/updates and on individual objects for deletions/updates.

Websocket connections multiplexing

Displaying live data from multiple sensors in a dashboard requires many statefull Websocket connections with the server. Multiplexing Websocket connections could be an efficient way to achieve it.

It could be done by sending messages from client to server indicating what streams to connect/disconnect as maps of IDs to URLs:

{
  "connect": {
    "1": "org-name/procedures/1563/streams/1/live",
    "2": "org-name/procedures/569/streams/1/live",
    "3": "org-name/procedures/33/streams/1/live"
  }
}

The server would then respond by multiplexing all messages in the same connection prefixing them with a 2-bytes message ID, corresponding to the index in the array.

It would even be possible to connect and/or disconnect sources dynamically w/o closing the websocket connection:

{
  connect": {
    "4": "procedures/111/streams/1/live"
  },
  disconnect: ["1", "2"]
}

URL paths could be relative to where the initial WS request was sent (i.e. at the root vs. on a particular procedure)

MQTT extension

MQTT connections can be made by using the URL path (up to the stream id) as the SUBSCRIBE topic (e.g. "org-name/procedures/temp_network/streams/temp"