diff --git a/generate_schema/common.json b/generate_schema/common.json new file mode 100644 index 000000000..8f507ff32 --- /dev/null +++ b/generate_schema/common.json @@ -0,0 +1,106 @@ +{ + "$id": "https://raw.githubusercontent.com/CityofLosAngeles/mobility-data-specification/master/provider/common.json", + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "The MDS Provider Schema, common definitions", + "type": "object", + "definitions": { + "version": { + "$id": "#/definitions/version", + "type": "string", + "title": "The MDS Provider version this data represents", + "examples": [ + "0.2.0" + ], + "pattern": "^0\\.2\\.[0-9]+$" + }, + "uuid": { + "$id": "#/definitions/uuid", + "type": "string", + "title": "A UUID 4 used to uniquely identifty an object", + "default": "", + "examples": [ + "3c9604d6-b5ee-11e8-96f8-529269fb1459" + ], + "format": "uri", + "pattern": "^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$" + }, + "propulsion_type": { + "$id": "#/definitions/propulsion_type", + "type": "array", + "description": "The type of propulsion; allows multiple values", + "items": { + "type": "string", + "enum": [ + "combustion", + "electric", + "electric_assist", + "human" + ] + }, + "minItems": 1 + }, + "vehicle_type": { + "$id": "#/definitions/vehicle_type", + "type": "string", + "description": "The type of vehicle", + "enum": [ + "bicycle", + "scooter" + ] + }, + "links": { + "$id": "#/definitions/links", + "type": "object", + "properties": { + "first": { + "$id": "#/definitions/links/first", + "type": "string", + "title": "The URL to the first page of data", + "examples": [ + "https://data.provider.co/trips/first" + ], + "format": "uri", + "pattern": "^(.*)$" + }, + "last": { + "$id": "#/definitions/links/last", + "type": "string", + "title": "The URL to the last page of data", + "examples": [ + "https://data.provider.co/trips/last" + ], + "format": "uri", + "pattern": "^(.*)$" + }, + "prev": { + "$id": "#/definitions/links/prev", + "type": "string", + "title": "The URL to the previous page of data", + "examples": [ + "https://data.provider.co/trips/prev" + ], + "format": "uri", + "pattern": "^(.*)$" + }, + "next": { + "$id": "#/definitions/links/next", + "type": "string", + "title": "The URL to the next page of data", + "default": "", + "examples": [ + "https://data.provider.co/trips/next" + ], + "format": "uri", + "pattern": "^(.*)$" + } + }, + "additionalProperties": false + }, + "timestamp": { + "$id": "#/definitions/timestamp", + "title": "Floating-point seconds since Unix epoch", + "type": "number", + "minimum": 0.0 + } + } +} diff --git a/generate_schema/generate_provider_schema.py b/generate_schema/generate_provider_schema.py new file mode 100644 index 000000000..7dcd33f34 --- /dev/null +++ b/generate_schema/generate_provider_schema.py @@ -0,0 +1,148 @@ +""" +generate_provider_schema.py + +When run, makes standalone schemas for the MDS provider API. +""" + +import json +import requests + +POINT = "Point" +MDS_FEATURE_POINT = "MDS_Feature_Point" +MDS_FEATURECOLLECTION_ROUTE = "MDS_FeatureCollection_Route" + +def get_definition(id): + return "#/definitions/{}".format(id) + +def get_point_schema(): + """ + Get the canonical schema for a GeoJSON point. + """ + p = requests.get("http://geojson.org/schema/Point.json") + point = p.json() + # Modify some metadata + point.pop("$schema") + point["$id"] = get_definition(POINT) + return point + +def get_feature_schema(id=None, title=None, geometry=None, properties=None, required=None): + """ + Get the canonical schema for a GeoJSON Feature, + and make any given modifications. + + :id: overrides the `$id` metadata + :title: overrides the `title` metadata + :geometry: overrides the allowed `geometry` for the Feature + :properties: overrides the `properties` definitions for this Feature + :required: is a list of required :properties: + """ + # Get the canonical Feature schema + f = requests.get("http://geojson.org/schema/Feature.json") + feature = f.json() + + # Modify some metadata + feature.pop("$schema") + if id is not None: + feature["$id"] = id + if title is not None: + feature["title"] = title + + if geometry is not None: + feature["properties"]["geometry"] = geometry + + f_properties = feature["properties"]["properties"] + if required is not None: + f_properties["required"] = required + if properties is not None: + f_properties["properties"] = properties + + return feature + +def get_feature_collection_schema(id=None, title=None, features=None): + """ + Get the canonical schema for a GeoJSON Feature Collection, + and make any given modifications. + + :id: overrides the `$id` metadata + :title: overrides the `title` metadata + :features: overrides the allowed `features` for the FeatureCollection + """ + # Get the canonical FeatureCollection schema + fc = requests.get("http://geojson.org/schema/FeatureCollection.json") + feature_collection = fc.json() + # Modify some metadata + feature_collection.pop("$schema") + if id is not None: + feature_collection["$id"] = id + if title is not None: + feature_collection["title"] = title + + if features is not None: + fc_features = feature_collection["properties"]["features"] + feature_collection["properties"]["features"] = { **fc_features, **features } + + return feature_collection + +def get_json_file(path): + """ + Load a JSON file from disk. + """ + with open(path) as f: + data = json.load(f) + return data + + +if __name__ == '__main__': + # Load common data + common = get_json_file('common.json') + point = get_point_schema() + # Craft the MDS specific types + mds_feature_point = get_feature_schema( + id = get_definition(MDS_FEATURE_POINT), + title = "MDS GeoJSON Feature Point", + # Only allow GeoJSON Point feature geometry + geometry = { "$ref": get_definition(POINT) }, + # Point features *must* include a `timestamp` property. + properties = { "timestamp": { "$ref": get_definition("timestamp") } }, + required = ["timestamp"] + ) + mds_feature_collection_route = get_feature_collection_schema( + id = get_definition(MDS_FEATURECOLLECTION_ROUTE), + title = "MDS GeoJSON FeatureCollection Route", + # 1. Only allow MDS Feature Points + # 2. There must be *at least* two Features in the FeatureCollection. + features = { "items": { "$ref": get_definition(MDS_FEATURE_POINT) }, "minItems": 2 } + ) + + + # Create the standalone trips JSON schema by including the needed definitions + trips = get_json_file('provider/trips.json') + trips["definitions"] = { + POINT: point, + MDS_FEATURE_POINT: mds_feature_point, + MDS_FEATURECOLLECTION_ROUTE: mds_feature_collection_route, + "links": common["definitions"]["links"], + "propulsion_type": common["definitions"]["propulsion_type"], + "vehicle_type": common["definitions"]["vehicle_type"], + "version": common["definitions"]["version"], + "uuid": common["definitions"]["uuid"], + } + # Write to the `provider` directory. + with open("../provider/trips.json", "w") as tripfile: + tripfile.write(json.dumps(trips, indent=2)) + + + # Create the standalone status_changes JSON schema by including the needed definitions + status_changes = get_json_file('provider/status_changes.json') + status_changes["definitions"] = { + POINT: point, + MDS_FEATURE_POINT: mds_feature_point, + "links": common["definitions"]["links"], + "propulsion_type": common["definitions"]["propulsion_type"], + "vehicle_type": common["definitions"]["vehicle_type"], + "version": common["definitions"]["version"], + "uuid": common["definitions"]["uuid"], + } + # Write to the `provider` directory. + with open("../provider/status_changes.json", "w") as statusfile: + statusfile.write(json.dumps(status_changes, indent=2)) diff --git a/generate_schema/provider/status_changes.json b/generate_schema/provider/status_changes.json new file mode 100644 index 000000000..2b1481c2d --- /dev/null +++ b/generate_schema/provider/status_changes.json @@ -0,0 +1,157 @@ +{ + "$id": "https://raw.githubusercontent.com/CityofLosAngeles/mobility-data-specification/master/provider/status_changes.json", + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "The MDS Provider Schema, status_change payload", + "type": "object", + "definitions": {}, + "required": [ + "version", + "data" + ], + "properties": { + "version": { + "$id": "#/properties/version", + "$ref": "#/definitions/version" + }, + "data": { + "$id": "#/properties/data", + "type": "object", + "title": "The page of data", + "required": [ + "status_changes" + ], + "properties": { + "status_changes": { + "$id": "#/properties/data/properties/status_changes", + "type": "array", + "title": "The status_changes Schema", + "items": { + "$id": "#/properties/data/properties/status_changes/items", + "type": "object", + "title": "The Items Schema", + "required": [ + "provider_name", + "provider_id", + "device_id", + "vehicle_id", + "vehicle_type", + "propulsion_type", + "event_type", + "event_type_reason", + "event_time", + "event_location" + ], + "properties": { + "provider_name": { + "$id": "#/properties/data/properties/status_changes/items/properties/provider_name", + "type": "string", + "description": "The public-facing name of the Provider", + "examples": [ + "Provider Name" + ], + "pattern": "^(.*)$" + }, + "provider_id": { + "$id": "#/properties/data/properties/status_changes/items/properties/provider_id", + "description": "The UUID for the Provider, unique within MDS", + "$ref": "#/definitions/uuid" + }, + "device_id": { + "$id": "#/properties/data/properties/status_changes/items/properties/device_id", + "description": "A unique device ID in UUID format", + "$ref": "#/definitions/uuid" + }, + "vehicle_id": { + "$id": "#/properties/data/properties/status_changes/items/properties/vehicle_id", + "type": "string", + "description": "The Vehicle Identification Number visible on the vehicle itself", + "default": "", + "examples": [ + "ABC123" + ], + "pattern": "^(.*)$" + }, + "vehicle_type": { + "$id": "#/properties/data/properties/status_changes/items/properties/vehicle_type", + "$ref": "#/definitions/vehicle_type", + "description": "The type of vehicle" + }, + "propulsion_type": { + "$id": "#/properties/data/properties/status_changes/items/properties/propulsion_type", + "description": "The type of propulsion; allows multiple values", + "$ref": "#/definitions/propulsion_type" + }, + "event_type": { + "$id": "#/properties/data/properties/status_changes/items/properties/event_type", + "type": "string", + "description": "The type of the event", + "enum": [ + "available", + "reserved", + "unavailable", + "removed" + ] + }, + "event_type_reason": { + "$id": "#/properties/data/properties/status_changes/items/properties/event_type_reason", + "type": "string", + "description": "The reason for the event", + "enum": [ + "service_start", + "user_drop_off", + "rebalance_drop_off", + "maintenance_drop_off", + "user_pick_up", + "maintenance", + "low_battery", + "service_end", + "rebalance_pick_up", + "maintenance_pick_up" + ] + }, + "event_time": { + "$id": "#/properties/data/properties/status_changes/items/properties/event_time", + "type": "number", + "description": "The time the event occurred, expressed as a Unix Timestamp", + "default": 0.0, + "examples": [ + 1529968782.421409 + ] + }, + "event_location": { + "$id": "#/properties/data/properties/status_changes/items/properties/event_location", + "description": "The GPS coordinates of where the event occurred", + "$ref": "#/definitions/FeatureMDS" + }, + "battery_pct": { + "$id": "#/properties/data/properties/status_changes/items/properties/battery_pct", + "type": "number", + "description": "Percent charge of device battery, expressed between 0 and 1", + "default": 0.0, + "examples": [ + 0.89 + ], + "minimum": 0, + "maximum": 1 + }, + "associated_trips": { + "$id": "#/properties/data/properties/status_changes/items/properties/associated_trips", + "type": "array", + "description": "For 'Reserved' event types, associated trip_ids", + "items": { + "$id": "#/properties/data/properties/status_changes/items/properties/associated_trips/items", + "$ref": "#/definitions/uuid" + } + } + } + } + } + } + }, + "links": { + "$id": "#properties/links", + "$ref": "#/definitions/links" + } + }, + "additionalProperties": false +} diff --git a/generate_schema/provider/trips.json b/generate_schema/provider/trips.json new file mode 100644 index 000000000..1b5074a3a --- /dev/null +++ b/generate_schema/provider/trips.json @@ -0,0 +1,181 @@ +{ + "$id": "https://raw.githubusercontent.com/CityofLosAngeles/mobility-data-specification/master/provider/trips.json", + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "The MDS Provider Schema, trips payload", + "type": "object", + "definitions": {}, + "required": [ + "version", + "data" + ], + "properties": { + "version": { + "$id": "#/properties/version", + "$ref": "#/definitions/version" + }, + "data": { + "$id": "#/properties/data", + "type": "object", + "title": "The page of data", + "required": [ + "trips" + ], + "properties": { + "trips": { + "$id": "#/properties/data/properties/trips", + "type": "array", + "title": "The Trips Schema", + "items": { + "$id": "#/properties/data/properties/trips/items", + "type": "object", + "title": "The Trip Schema", + "required": [ + "provider_name", + "provider_id", + "device_id", + "vehicle_id", + "vehicle_type", + "propulsion_type", + "trip_id", + "trip_duration", + "trip_distance", + "route", + "accuracy", + "start_time", + "end_time" + ], + "properties": { + "provider_name": { + "$id": "#/properties/data/properties/trips/items/properties/provider_name", + "type": "string", + "description": "The public-facing name of the Provider", + "examples": [ + "Provider Name" + ], + "pattern": "^(.*)$" + }, + "provider_id": { + "$id": "#/properties/data/properties/trips/items/properties/provider_id", + "description": "The UUID for the Provider, unique within MDS", + "$ref": "#/definitions/uuid" + }, + "device_id": { + "$id": "#/properties/data/properties/trips/items/properties/device_id", + "$ref": "#/definitions/uuid", + "description": "A unique device ID in UUID format" + }, + "vehicle_id": { + "$id": "#/properties/data/properties/trips/items/properties/vehicle_id", + "type": "string", + "description": "The Vehicle Identification Number visible on the vehicle itself", + "default": "", + "examples": [ + "ABC123" + ], + "pattern": "^(.*)$" + }, + "vehicle_type": { + "$id": "#/properties/data/properties/trips/items/properties/vehicle_type", + "$ref": "#/definitions/vehicle_type", + "description": "The type of vehicle" + }, + "propulsion_type": { + "$id": "#/properties/data/properties/trips/items/properties/propulsion_type", + "description": "The type of propulsion; allows multiple values", + "$ref": "#/definitions/propulsion_type" + }, + "trip_id": { + "$id": "#/properties/data/properties/trips/items/properties/trip_id", + "description": "A unique ID for each trip", + "$ref": "#/definitions/uuid" + }, + "trip_duration": { + "$id": "#/properties/data/properties/trips/items/properties/trip_duration", + "type": "integer", + "description": "The length of time, in seconds, that the trip lasted", + "default": 0, + "examples": [ + 600 + ] + }, + "trip_distance": { + "$id": "#/properties/data/properties/trips/items/properties/trip_distance", + "type": "integer", + "description": "The distance, in meters, that the trip covered", + "default": 0, + "examples": [ + 1000 + ] + }, + "route": { + "$id": "#/properties/data/properties/trips/items/properties/route", + "title": "The Route Schema", + "$ref": "#/definitions/FeatureCollectionMDS" + }, + "accuracy": { + "$id": "#/properties/data/properties/trips/items/properties/accuracy", + "type": "integer", + "title": "The approximate level of accuracy, in meters, of Points within route", + "default": 0, + "examples": [ + 15 + ] + }, + "start_time": { + "$id": "#/properties/data/properties/trips/items/properties/start_time", + "type": "number", + "description": "The time the trip began, expressed as a Unix Timestamp", + "default": 0.0, + "examples": [ + 1529968782.421409 + ] + }, + "end_time": { + "$id": "#/properties/data/properties/trips/items/properties/end_time", + "type": "number", + "description": "The time the trip ended, expressed as a Unix Timestamp", + "default": 0.0, + "examples": [ + 1531007628.3774529 + ] + }, + "parking_verification_url": { + "$id": "#/properties/data/properties/trips/items/properties/parking_verification_url", + "type": "string", + "description": "A URL to a photo (or other evidence) of proper vehicle parking", + "default": "", + "examples": [ + "https://data.provider.co/parking_verify/1234.jpg" + ], + "pattern": "^(https://.*)$" + }, + "standard_cost": { + "$id": "#/properties/data/properties/trips/items/properties/standard_cost", + "type": "integer", + "description": "The cost, in cents, that it would cost to perform the trip in the standard operation of the System", + "default": 0, + "examples": [ + 500 + ] + }, + "actual_cost": { + "$id": "#/properties/data/properties/trips/items/properties/actual_cost", + "type": "integer", + "description": "The actual cost, in cents, paid by the customer of the mobility as a service provider", + "default": 0, + "examples": [ + 520 + ] + } + } + } + } + } + }, + "links": { + "$id": "#properties/links", + "$ref": "#/definitions/links" + } + }, + "additionalProperties": false +} diff --git a/provider/README.md b/provider/README.md index a8ec0df73..ced8b5695 100644 --- a/provider/README.md +++ b/provider/README.md @@ -16,14 +16,13 @@ The following information applies to all `provider` API endpoints. Details on pr Responses must be `UTF-8` encoded `application/json` and must minimally include the MDS `version` and a `data` payload: -```js +```json { - "version": "0.1.0", + "version": "x.y.z", "data": { "trips": [{ "provider_id": "...", "trip_id": "...", - //etc. }] } } @@ -31,6 +30,12 @@ Responses must be `UTF-8` encoded `application/json` and must minimally include All response fields must use `lower_case_with_underscores`. +#### JSON Schema + +MDS defines [JSON Schema](https://json-schema.org/) files for [`trips`][trips-schema] and [`status_changes`][sc-schema]. + +`provider` API responses must validate against their respective schema files. The schema files always take precedence over the language and examples in this and other supporting documentation meant for *human* consumption. + ### Pagination `provider` APIs may decide to paginate the data payload. If so, pagination must comply with the [JSON API](http://jsonapi.org/format/#fetching-pagination) specification. @@ -42,14 +47,13 @@ The following keys must be used for pagination links: * `prev`: url to the previous page of data * `next`: url to the next page of data -```js +```json { - "version": "0.1.0", + "version": "x.y.z", "data": { "trips": [{ "provider_id": "...", "trip_id": "...", - //etc. }] }, "links": { @@ -63,7 +67,7 @@ The following keys must be used for pagination links: ### UUIDs for Devices -**MDS** defines the *device* as the unit that transmits GPS signals for a particular vehicle. A given device must have a UUID (`device_id` below) that is unique within the Provider's fleet. +MDS defines the *device* as the unit that transmits GPS signals for a particular vehicle. A given device must have a UUID (`device_id` below) that is unique within the Provider's fleet. Additionally, `device_id` must remain constant for the device's lifetime of service, regardless of the vehicle components that house the device. @@ -107,7 +111,7 @@ The trips API allows a user to query historical trip data. Endpoint: `/trips` Method: `GET` -Data: `{ "trips": [] }`, an array of objects with the following structure +Response: See the [`trips` schema][trips-schema] for the expected format. | Field | Type | Required/Optional | Comments | | ----- | -------- | ----------------- | ----- | @@ -212,7 +216,7 @@ This API allows a user to query the historical availability for a system within Endpoint: `/status_changes` Method: `GET` -Data: `{ "status_changes": [] }`, an array of objects with the following structure +Response: See the [`status_changes` schema][sc-schema] for the expected format. | Field | Type | Required/Optional | Comments | | ----- | ---- | ----------------- | ----- | @@ -270,5 +274,7 @@ All MDS compatible `provider` APIs must expose a [GBFS](https://github.com/NABSA [Top][toc] [geo]: #geographic-data +[sc-schema]: status_changes.json [toc]: #table-of-contents -[ts]: #timestamps \ No newline at end of file +[trips-schema]: trips.json +[ts]: #timestamps diff --git a/provider/status_changes.json b/provider/status_changes.json new file mode 100644 index 000000000..37591788e --- /dev/null +++ b/provider/status_changes.json @@ -0,0 +1,320 @@ +{ + "$id": "https://raw.githubusercontent.com/CityofLosAngeles/mobility-data-specification/master/provider/status_changes.json", + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "The MDS Provider Schema, status_change payload", + "type": "object", + "definitions": { + "Point": { + "$id": "#/definitions/Point", + "title": "GeoJSON Point", + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "Point" + ] + }, + "coordinates": { + "type": "array", + "minItems": 2, + "items": { + "type": "number" + } + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + }, + "MDS_Feature_Point": { + "$id": "#/definitions/MDS_Feature_Point", + "title": "MDS GeoJSON Feature Point", + "type": "object", + "required": [ + "type", + "properties", + "geometry" + ], + "properties": { + "type": { + "type": "string", + "emum": [ + "Feature" + ] + }, + "properties": { + "type": "object", + "required": [ + "timestamp" + ], + "properties": { + "timestamp": { + "$ref": "#/definitions/timestamp" + } + } + }, + "geometry": { + "$ref": "#/definitions/Point" + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + }, + "links": { + "$id": "#/definitions/links", + "type": "object", + "properties": { + "first": { + "$id": "#/definitions/links/first", + "type": "string", + "title": "The URL to the first page of data", + "examples": [ + "https://data.provider.co/trips/first" + ], + "format": "uri", + "pattern": "^(.*)$" + }, + "last": { + "$id": "#/definitions/links/last", + "type": "string", + "title": "The URL to the last page of data", + "examples": [ + "https://data.provider.co/trips/last" + ], + "format": "uri", + "pattern": "^(.*)$" + }, + "prev": { + "$id": "#/definitions/links/prev", + "type": "string", + "title": "The URL to the previous page of data", + "examples": [ + "https://data.provider.co/trips/prev" + ], + "format": "uri", + "pattern": "^(.*)$" + }, + "next": { + "$id": "#/definitions/links/next", + "type": "string", + "title": "The URL to the next page of data", + "default": "", + "examples": [ + "https://data.provider.co/trips/next" + ], + "format": "uri", + "pattern": "^(.*)$" + } + }, + "additionalProperties": false + }, + "propulsion_type": { + "$id": "#/definitions/propulsion_type", + "type": "array", + "description": "The type of propulsion; allows multiple values", + "items": { + "type": "string", + "enum": [ + "combustion", + "electric", + "electric_assist", + "human" + ] + }, + "minItems": 1 + }, + "vehicle_type": { + "$id": "#/definitions/vehicle_type", + "type": "string", + "description": "The type of vehicle", + "enum": [ + "bicycle", + "scooter" + ] + }, + "version": { + "$id": "#/definitions/version", + "type": "string", + "title": "The MDS Provider version this data represents", + "examples": [ + "0.2.0" + ], + "pattern": "^0\\.2\\.[0-9]+$" + }, + "uuid": { + "$id": "#/definitions/uuid", + "type": "string", + "title": "A UUID 4 used to uniquely identifty an object", + "default": "", + "examples": [ + "3c9604d6-b5ee-11e8-96f8-529269fb1459" + ], + "format": "uri", + "pattern": "^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$" + } + }, + "required": [ + "version", + "data" + ], + "properties": { + "version": { + "$id": "#/properties/version", + "$ref": "#/definitions/version" + }, + "data": { + "$id": "#/properties/data", + "type": "object", + "title": "The page of data", + "required": [ + "status_changes" + ], + "properties": { + "status_changes": { + "$id": "#/properties/data/properties/status_changes", + "type": "array", + "title": "The status_changes Schema", + "items": { + "$id": "#/properties/data/properties/status_changes/items", + "type": "object", + "title": "The Items Schema", + "required": [ + "provider_name", + "provider_id", + "device_id", + "vehicle_id", + "vehicle_type", + "propulsion_type", + "event_type", + "event_type_reason", + "event_time", + "event_location" + ], + "properties": { + "provider_name": { + "$id": "#/properties/data/properties/status_changes/items/properties/provider_name", + "type": "string", + "description": "The public-facing name of the Provider", + "examples": [ + "Provider Name" + ], + "pattern": "^(.*)$" + }, + "provider_id": { + "$id": "#/properties/data/properties/status_changes/items/properties/provider_id", + "description": "The UUID for the Provider, unique within MDS", + "$ref": "#/definitions/uuid" + }, + "device_id": { + "$id": "#/properties/data/properties/status_changes/items/properties/device_id", + "description": "A unique device ID in UUID format", + "$ref": "#/definitions/uuid" + }, + "vehicle_id": { + "$id": "#/properties/data/properties/status_changes/items/properties/vehicle_id", + "type": "string", + "description": "The Vehicle Identification Number visible on the vehicle itself", + "default": "", + "examples": [ + "ABC123" + ], + "pattern": "^(.*)$" + }, + "vehicle_type": { + "$id": "#/properties/data/properties/status_changes/items/properties/vehicle_type", + "$ref": "#/definitions/vehicle_type", + "description": "The type of vehicle" + }, + "propulsion_type": { + "$id": "#/properties/data/properties/status_changes/items/properties/propulsion_type", + "description": "The type of propulsion; allows multiple values", + "$ref": "#/definitions/propulsion_type" + }, + "event_type": { + "$id": "#/properties/data/properties/status_changes/items/properties/event_type", + "type": "string", + "description": "The type of the event", + "enum": [ + "available", + "reserved", + "unavailable", + "removed" + ] + }, + "event_type_reason": { + "$id": "#/properties/data/properties/status_changes/items/properties/event_type_reason", + "type": "string", + "description": "The reason for the event", + "enum": [ + "service_start", + "user_drop_off", + "rebalance_drop_off", + "maintenance_drop_off", + "user_pick_up", + "maintenance", + "low_battery", + "service_end", + "rebalance_pick_up", + "maintenance_pick_up" + ] + }, + "event_time": { + "$id": "#/properties/data/properties/status_changes/items/properties/event_time", + "type": "number", + "description": "The time the event occurred, expressed as a Unix Timestamp", + "default": 0.0, + "examples": [ + 1529968782.421409 + ] + }, + "event_location": { + "$id": "#/properties/data/properties/status_changes/items/properties/event_location", + "description": "The GPS coordinates of where the event occurred", + "$ref": "#/definitions/FeatureMDS" + }, + "battery_pct": { + "$id": "#/properties/data/properties/status_changes/items/properties/battery_pct", + "type": "number", + "description": "Percent charge of device battery, expressed between 0 and 1", + "default": 0.0, + "examples": [ + 0.89 + ], + "minimum": 0, + "maximum": 1 + }, + "associated_trips": { + "$id": "#/properties/data/properties/status_changes/items/properties/associated_trips", + "type": "array", + "description": "For 'Reserved' event types, associated trip_ids", + "items": { + "$id": "#/properties/data/properties/status_changes/items/properties/associated_trips/items", + "$ref": "#/definitions/uuid" + } + } + } + } + } + } + }, + "links": { + "$id": "#properties/links", + "$ref": "#/definitions/links" + } + }, + "additionalProperties": false +} \ No newline at end of file diff --git a/provider/trips.json b/provider/trips.json new file mode 100644 index 000000000..36fb11e0d --- /dev/null +++ b/provider/trips.json @@ -0,0 +1,375 @@ +{ + "$id": "https://raw.githubusercontent.com/CityofLosAngeles/mobility-data-specification/master/provider/trips.json", + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "The MDS Provider Schema, trips payload", + "type": "object", + "definitions": { + "Point": { + "$id": "#/definitions/Point", + "title": "GeoJSON Point", + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "Point" + ] + }, + "coordinates": { + "type": "array", + "minItems": 2, + "items": { + "type": "number" + } + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + }, + "MDS_Feature_Point": { + "$id": "#/definitions/MDS_Feature_Point", + "title": "MDS GeoJSON Feature Point", + "type": "object", + "required": [ + "type", + "properties", + "geometry" + ], + "properties": { + "type": { + "type": "string", + "emum": [ + "Feature" + ] + }, + "properties": { + "type": "object", + "required": [ + "timestamp" + ], + "properties": { + "timestamp": { + "$ref": "#/definitions/timestamp" + } + } + }, + "geometry": { + "$ref": "#/definitions/Point" + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + }, + "MDS_FeatureCollection_Route": { + "$id": "#/definitions/MDS_FeatureCollection_Route", + "title": "MDS GeoJSON FeatureCollection Route", + "type": "object", + "required": [ + "type", + "features" + ], + "properties": { + "type": { + "type": "string", + "emum": [ + "FeatureCollection" + ] + }, + "features": { + "type": "array", + "items": { + "$ref": "#/definitions/MDS_Feature_Point" + }, + "minItems": 2 + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + }, + "links": { + "$id": "#/definitions/links", + "type": "object", + "properties": { + "first": { + "$id": "#/definitions/links/first", + "type": "string", + "title": "The URL to the first page of data", + "examples": [ + "https://data.provider.co/trips/first" + ], + "format": "uri", + "pattern": "^(.*)$" + }, + "last": { + "$id": "#/definitions/links/last", + "type": "string", + "title": "The URL to the last page of data", + "examples": [ + "https://data.provider.co/trips/last" + ], + "format": "uri", + "pattern": "^(.*)$" + }, + "prev": { + "$id": "#/definitions/links/prev", + "type": "string", + "title": "The URL to the previous page of data", + "examples": [ + "https://data.provider.co/trips/prev" + ], + "format": "uri", + "pattern": "^(.*)$" + }, + "next": { + "$id": "#/definitions/links/next", + "type": "string", + "title": "The URL to the next page of data", + "default": "", + "examples": [ + "https://data.provider.co/trips/next" + ], + "format": "uri", + "pattern": "^(.*)$" + } + }, + "additionalProperties": false + }, + "propulsion_type": { + "$id": "#/definitions/propulsion_type", + "type": "array", + "description": "The type of propulsion; allows multiple values", + "items": { + "type": "string", + "enum": [ + "combustion", + "electric", + "electric_assist", + "human" + ] + }, + "minItems": 1 + }, + "vehicle_type": { + "$id": "#/definitions/vehicle_type", + "type": "string", + "description": "The type of vehicle", + "enum": [ + "bicycle", + "scooter" + ] + }, + "version": { + "$id": "#/definitions/version", + "type": "string", + "title": "The MDS Provider version this data represents", + "examples": [ + "0.2.0" + ], + "pattern": "^0\\.2\\.[0-9]+$" + }, + "uuid": { + "$id": "#/definitions/uuid", + "type": "string", + "title": "A UUID 4 used to uniquely identifty an object", + "default": "", + "examples": [ + "3c9604d6-b5ee-11e8-96f8-529269fb1459" + ], + "format": "uri", + "pattern": "^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$" + } + }, + "required": [ + "version", + "data" + ], + "properties": { + "version": { + "$id": "#/properties/version", + "$ref": "#/definitions/version" + }, + "data": { + "$id": "#/properties/data", + "type": "object", + "title": "The page of data", + "required": [ + "trips" + ], + "properties": { + "trips": { + "$id": "#/properties/data/properties/trips", + "type": "array", + "title": "The Trips Schema", + "items": { + "$id": "#/properties/data/properties/trips/items", + "type": "object", + "title": "The Trip Schema", + "required": [ + "provider_name", + "provider_id", + "device_id", + "vehicle_id", + "vehicle_type", + "propulsion_type", + "trip_id", + "trip_duration", + "trip_distance", + "route", + "accuracy", + "start_time", + "end_time" + ], + "properties": { + "provider_name": { + "$id": "#/properties/data/properties/trips/items/properties/provider_name", + "type": "string", + "description": "The public-facing name of the Provider", + "examples": [ + "Provider Name" + ], + "pattern": "^(.*)$" + }, + "provider_id": { + "$id": "#/properties/data/properties/trips/items/properties/provider_id", + "description": "The UUID for the Provider, unique within MDS", + "$ref": "#/definitions/uuid" + }, + "device_id": { + "$id": "#/properties/data/properties/trips/items/properties/device_id", + "$ref": "#/definitions/uuid", + "description": "A unique device ID in UUID format" + }, + "vehicle_id": { + "$id": "#/properties/data/properties/trips/items/properties/vehicle_id", + "type": "string", + "description": "The Vehicle Identification Number visible on the vehicle itself", + "default": "", + "examples": [ + "ABC123" + ], + "pattern": "^(.*)$" + }, + "vehicle_type": { + "$id": "#/properties/data/properties/trips/items/properties/vehicle_type", + "$ref": "#/definitions/vehicle_type", + "description": "The type of vehicle" + }, + "propulsion_type": { + "$id": "#/properties/data/properties/trips/items/properties/propulsion_type", + "description": "The type of propulsion; allows multiple values", + "$ref": "#/definitions/propulsion_type" + }, + "trip_id": { + "$id": "#/properties/data/properties/trips/items/properties/trip_id", + "description": "A unique ID for each trip", + "$ref": "#/definitions/uuid" + }, + "trip_duration": { + "$id": "#/properties/data/properties/trips/items/properties/trip_duration", + "type": "integer", + "description": "The length of time, in seconds, that the trip lasted", + "default": 0, + "examples": [ + 600 + ] + }, + "trip_distance": { + "$id": "#/properties/data/properties/trips/items/properties/trip_distance", + "type": "integer", + "description": "The distance, in meters, that the trip covered", + "default": 0, + "examples": [ + 1000 + ] + }, + "route": { + "$id": "#/properties/data/properties/trips/items/properties/route", + "title": "The Route Schema", + "$ref": "#/definitions/FeatureCollectionMDS" + }, + "accuracy": { + "$id": "#/properties/data/properties/trips/items/properties/accuracy", + "type": "integer", + "title": "The approximate level of accuracy, in meters, of Points within route", + "default": 0, + "examples": [ + 15 + ] + }, + "start_time": { + "$id": "#/properties/data/properties/trips/items/properties/start_time", + "type": "number", + "description": "The time the trip began, expressed as a Unix Timestamp", + "default": 0.0, + "examples": [ + 1529968782.421409 + ] + }, + "end_time": { + "$id": "#/properties/data/properties/trips/items/properties/end_time", + "type": "number", + "description": "The time the trip ended, expressed as a Unix Timestamp", + "default": 0.0, + "examples": [ + 1531007628.3774529 + ] + }, + "parking_verification_url": { + "$id": "#/properties/data/properties/trips/items/properties/parking_verification_url", + "type": "string", + "description": "A URL to a photo (or other evidence) of proper vehicle parking", + "default": "", + "examples": [ + "https://data.provider.co/parking_verify/1234.jpg" + ], + "pattern": "^(https://.*)$" + }, + "standard_cost": { + "$id": "#/properties/data/properties/trips/items/properties/standard_cost", + "type": "integer", + "description": "The cost, in cents, that it would cost to perform the trip in the standard operation of the System", + "default": 0, + "examples": [ + 500 + ] + }, + "actual_cost": { + "$id": "#/properties/data/properties/trips/items/properties/actual_cost", + "type": "integer", + "description": "The actual cost, in cents, paid by the customer of the mobility as a service provider", + "default": 0, + "examples": [ + 520 + ] + } + } + } + } + } + }, + "links": { + "$id": "#properties/links", + "$ref": "#/definitions/links" + } + }, + "additionalProperties": false +} \ No newline at end of file