diff --git a/README.md b/README.md index 4c018bb61..9a9cdfb2a 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ The Mobility Data Specification (**MDS**), a project of the [Open Mobility Found ## Endpoints -**MDS** is currently comprised of three distinct components: +**MDS** is currently comprised of four distinct components: * The [`provider`][provider] API endpoints are intended to be implemented by mobility providers and consumed by regulatory agencies. When a municipality queries information from a mobility provider, the Provider API has a historical view of operations in a standard format. It was first released in June 2018. Development takes place under the guidance of the OMF's Provider Services Working Group. @@ -31,6 +31,8 @@ The Mobility Data Specification (**MDS**), a project of the [Open Mobility Found * The [`policy`][policy] API endpoints are intended to be implemented by regulatory agencies and consumed by mobility providers. Providers query the Policy API to get information about local rules that may affect the operation of their mobility service or which may be used to determine compliance. It was first released in October 2019. Development takes place under the guidance of the OMF's City Services Working Group. +* The [`geography`][geography] API endpoints are intended to be implemented by regulatory agencies and consumed by mobility providers. Providers query the Policy API to get information about geographical regions for regulatory and other purposes. It was first released in October 2019, originally included as part of the Policy specification. Development takes place under the guidance of the OMF's City Services Working Group. + MDS is designed to be a modular kit-of-parts. Regulatory agencies can use the components of the API that are appropriate for their needs. An agency may choose to use only `agency`, `provider`, or `policy`. Or they may select specific elements (endpoints) from each to help them implement their goals. Many parts of the MDS definitions and APIs align across each other. In these cases, consolidated information can be found on the [General Information](/general-information.md) page. @@ -170,4 +172,5 @@ Please open a pull request if you create open source or private tools for implem [agency]: /agency/README.md [provider]: /provider/README.md [policy]: /policy/README.md +[geography]: /geography/README.md [toc]: #table-of-contents diff --git a/geography/README.md b/geography/README.md new file mode 100644 index 000000000..fa2d37378 --- /dev/null +++ b/geography/README.md @@ -0,0 +1,148 @@ +# Mobility Data Specification: Geography + +This specification contains a collection of RESTful APIs used to read Geographies (descriptions of geographical information, e.g. multi-polygons, currently represented via GeoJSON). + +Geographical data has many applications in the context of mobility, such as the description of municipal boundaries, locations for pick-up and drop-off zones, and areas of temporary closure for special events or emergencies. This API is intended to support a variety of other APIs, including the Policy API. + +Geographical data will be stored as GeoJSON and read from either `geographies.json` or the `/geographies` endpoint, referenced by UUID. Geography data once published through this API shall be treated as immutable, to ensure that any rules or regulations referring to the boundaries cannot be retroactively changed. A Geography may be deprecated and replaced by updated version with a new UUID. +Obsoleting or otherwise changing a geography is accomplished by publishing a new geography with a field named `prev_geographies`, a list of UUID references to the geography or geographies superseded by the new geography. + +## Table of Contents + +* [General Information](#general-information) + * [Versioning](#versioning) + * [Response Format](#repsonse-format) + * [Authorization](#authorization) +* [Distribution](#distribution) +* [Schema](#schema) + * [Geography Fields](#geography-fields) +* [File Format](#file-format) +* [Endpoints](#endpoints) + +## General Information + +### Versioning + +MDS APIs must handle requests for specific versions of the specification from clients. + +Versioning must be implemented as specified in the [Versioning section][versioning]. + +### Response Format + +See the [Responses][responses] and [Error Messages][error-messages] sections. + +### Authorization + +When making requests, the Geography API expects `provider_id` to be part of the claims in a [JWT](https://jwt.io/) `access_token` in the `Authorization` header, in the form `Authorization: Bearer `. The token issuance, expiration and revocation policies are at the discretion of the Agency. + + + +## Schema + +Placeholder -- schema to be added. + +### Geography Fields + +| Name | Type | Required/Optional | Description | +| ---------------- | --------- | --- | ----------------------------------------------------------------------------------- | +| `name` | String | Required | Name of geography | +| `description` | String | Optional | Detailed description of geography | +| `geography_id` | UUID | Required | Unique ID of geography | +| `geography_json` | UUID | Required | The GeoJSON that defines the geographical coordinates. +| `effective_date` | [timestamp][ts] | Optional | The date at which a Geography is considered "live". Must be at or after `publish_date`. +| `publish_date` | [timestamp][ts] | Required | Timestamp that the policy was published, i.e. made immutable | +| `prev_geographies` | UUID[] | Optional | Unique IDs of prior geographies replaced by this one | + + + +## File format + +To use flat files rather than REST endpoints, Geography objects should be stored in `geographies.json`. The `geographies.json` file will look like the output of `GET /geographies`. + +Example `geographies.json` +```json +{ + "version": "0.4.0", + "updated:" "1570035222868", + "geographies": [ + { + // GeoJSON 1 + }, + { + // GeoJSON 2 + } + ] +} +``` + + + +## REST Endpoints + +Responses must set the `Content-Type` header, as specified in the [Provider versioning](../provider/README.md#versioning) section. They must also specify the API version in the JSON-formatted response body, under the `version` key. + +The Geography Author API consists of the following endpoints: + +**Endpoint**: `/geographies/{geography_id}` + +**Method**: `GET` + +Path Params: + +| Name | Type | Required/Optional | Description | +| ------------- | ---- | --- | --------------------------------------------------- | +| geography_id | UUID | Required | Unique identifier for a single specific Geography | + +Returns: A single Geography. + +Response body: +```js +{ + version: '1.0.0', + geography: { + geography_id: UUID, + geography_json: GeoJSON FeatureCollection, + prev_geographies: UUID[], + name: string, + publish_date: timestamp + effective_date: timestamp + description: string + } +} +``` + +Response codes: +- 200 - success +- 401 - unauthorized +- 404 - no geography found +- 403 - user is attempting to read an unpublished geography, but only has the `geographies:read:published` scope. + +**Endpoint**: `/geographies` +**Method**: `GET` + +Path Params: + +| Name | Type | Required/Optional | Description | +| ------------ | --------- | --- | ---------------------------------------------- | +| `summary` | string | Optional | Return geographies, minus the GeoJSON in each geography object | + +Returns: All non-deprecated geography objects + +Response body: +```js +{ + version: '0.1.0', + geographies: { + Geography[] + } +} +``` + +Response codes: +- 200 - success +- 401 - unauthorized + +[error-messages]: /general-information.md#error-messages +[responses]: /general-information.md#responses +[ts]: /general-information.md#timestamps +[versioning]: /general-information.md#versioning \ No newline at end of file diff --git a/geography/get_geography.json b/geography/get_geography.json new file mode 100644 index 000000000..83a5e2f68 --- /dev/null +++ b/geography/get_geography.json @@ -0,0 +1,1038 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "The MDS Geography Author Schema, GET /geographies/{id} payload", + "definitions": { + "GeoJSON.Feature": { + "description": "A feature object which contains a geometry and associated properties.\nhttps://tools.ietf.org/html/rfc7946#section-3.2", + "properties": { + "bbox": { + "anyOf": [ + { + "additionalItems": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "minItems": 4, + "type": "array" + }, + { + "additionalItems": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "minItems": 6, + "type": "array" + } + ], + "description": "Bounding box of the coordinate range of the object's Geometries, Features, or Feature Collections.\nThe value of the bbox member is an array of length 2*n where n is the number of dimensions\nrepresented in the contained geometries, with all axes of the most southwesterly point\nfollowed by all axes of the more northeasterly point.\nThe axes order of a bbox follows the axes order of geometries.\nhttps://tools.ietf.org/html/rfc7946#section-5" + }, + "geometry": { + "anyOf": [ + { + "$ref": "#/definitions/GeoJSON.Point" + }, + { + "$ref": "#/definitions/GeoJSON.MultiPoint" + }, + { + "$ref": "#/definitions/GeoJSON.LineString" + }, + { + "$ref": "#/definitions/GeoJSON.MultiLineString" + }, + { + "$ref": "#/definitions/GeoJSON.Polygon" + }, + { + "$ref": "#/definitions/GeoJSON.MultiPolygon" + }, + { + "$ref": "#/definitions/GeoJSON.GeometryCollection" + } + ], + "description": "The feature's geometry" + }, + "id": { + "description": "A value that uniquely identifies this feature in a\nhttps://tools.ietf.org/html/rfc7946#section-3.2.", + "type": [ + "string", + "number" + ] + }, + "properties": { + "additionalProperties": {}, + "description": "Properties associated with this feature.", + "type": "object" + }, + "type": { + "description": "Specifies the type of GeoJSON object.", + "enum": [ + "Feature" + ], + "type": "string" + } + }, + "type": "object" + }, + "GeoJSON.FeatureCollection": { + "description": "A collection of feature objects.\n https://tools.ietf.org/html/rfc7946#section-3.3", + "properties": { + "bbox": { + "anyOf": [ + { + "additionalItems": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "minItems": 4, + "type": "array" + }, + { + "additionalItems": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "minItems": 6, + "type": "array" + } + ], + "description": "Bounding box of the coordinate range of the object's Geometries, Features, or Feature Collections.\nThe value of the bbox member is an array of length 2*n where n is the number of dimensions\nrepresented in the contained geometries, with all axes of the most southwesterly point\nfollowed by all axes of the more northeasterly point.\nThe axes order of a bbox follows the axes order of geometries.\nhttps://tools.ietf.org/html/rfc7946#section-5" + }, + "features": { + "items": { + "$ref": "#/definitions/GeoJSON.Feature" + }, + "type": "array" + }, + "type": { + "description": "Specifies the type of GeoJSON object.", + "enum": [ + "FeatureCollection" + ], + "type": "string" + } + }, + "type": "object" + }, + "GeoJSON.GeometryCollection": { + "description": "Geometry Collection\nhttps://tools.ietf.org/html/rfc7946#section-3.1.8", + "properties": { + "bbox": { + "anyOf": [ + { + "additionalItems": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "minItems": 4, + "type": "array" + }, + { + "additionalItems": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "minItems": 6, + "type": "array" + } + ], + "description": "Bounding box of the coordinate range of the object's Geometries, Features, or Feature Collections.\nThe value of the bbox member is an array of length 2*n where n is the number of dimensions\nrepresented in the contained geometries, with all axes of the most southwesterly point\nfollowed by all axes of the more northeasterly point.\nThe axes order of a bbox follows the axes order of geometries.\nhttps://tools.ietf.org/html/rfc7946#section-5" + }, + "geometries": { + "items": { + "anyOf": [ + { + "$ref": "#/definitions/GeoJSON.Point" + }, + { + "$ref": "#/definitions/GeoJSON.MultiPoint" + }, + { + "$ref": "#/definitions/GeoJSON.LineString" + }, + { + "$ref": "#/definitions/GeoJSON.MultiLineString" + }, + { + "$ref": "#/definitions/GeoJSON.Polygon" + }, + { + "$ref": "#/definitions/GeoJSON.MultiPolygon" + }, + { + "$ref": "#/definitions/GeoJSON.GeometryCollection" + } + ] + }, + "type": "array" + }, + "type": { + "description": "Specifies the type of GeoJSON object.", + "enum": [ + "GeometryCollection" + ], + "type": "string" + } + }, + "type": "object" + }, + "GeoJSON.LineString": { + "description": "LineString geometry object.\nhttps://tools.ietf.org/html/rfc7946#section-3.1.4", + "properties": { + "bbox": { + "anyOf": [ + { + "additionalItems": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "minItems": 4, + "type": "array" + }, + { + "additionalItems": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "minItems": 6, + "type": "array" + } + ], + "description": "Bounding box of the coordinate range of the object's Geometries, Features, or Feature Collections.\nThe value of the bbox member is an array of length 2*n where n is the number of dimensions\nrepresented in the contained geometries, with all axes of the most southwesterly point\nfollowed by all axes of the more northeasterly point.\nThe axes order of a bbox follows the axes order of geometries.\nhttps://tools.ietf.org/html/rfc7946#section-5" + }, + "coordinates": { + "items": { + "items": { + "type": "number" + }, + "type": "array" + }, + "type": "array" + }, + "type": { + "description": "Specifies the type of GeoJSON object.", + "enum": [ + "LineString" + ], + "type": "string" + } + }, + "type": "object" + }, + "GeoJSON.MultiLineString": { + "description": "MultiLineString geometry object.\nhttps://tools.ietf.org/html/rfc7946#section-3.1.5", + "properties": { + "bbox": { + "anyOf": [ + { + "additionalItems": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "minItems": 4, + "type": "array" + }, + { + "additionalItems": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "minItems": 6, + "type": "array" + } + ], + "description": "Bounding box of the coordinate range of the object's Geometries, Features, or Feature Collections.\nThe value of the bbox member is an array of length 2*n where n is the number of dimensions\nrepresented in the contained geometries, with all axes of the most southwesterly point\nfollowed by all axes of the more northeasterly point.\nThe axes order of a bbox follows the axes order of geometries.\nhttps://tools.ietf.org/html/rfc7946#section-5" + }, + "coordinates": { + "items": { + "items": { + "items": { + "type": "number" + }, + "type": "array" + }, + "type": "array" + }, + "type": "array" + }, + "type": { + "description": "Specifies the type of GeoJSON object.", + "enum": [ + "MultiLineString" + ], + "type": "string" + } + }, + "type": "object" + }, + "GeoJSON.MultiPoint": { + "description": "MultiPoint geometry object.\n https://tools.ietf.org/html/rfc7946#section-3.1.3", + "properties": { + "bbox": { + "anyOf": [ + { + "additionalItems": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "minItems": 4, + "type": "array" + }, + { + "additionalItems": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "minItems": 6, + "type": "array" + } + ], + "description": "Bounding box of the coordinate range of the object's Geometries, Features, or Feature Collections.\nThe value of the bbox member is an array of length 2*n where n is the number of dimensions\nrepresented in the contained geometries, with all axes of the most southwesterly point\nfollowed by all axes of the more northeasterly point.\nThe axes order of a bbox follows the axes order of geometries.\nhttps://tools.ietf.org/html/rfc7946#section-5" + }, + "coordinates": { + "items": { + "items": { + "type": "number" + }, + "type": "array" + }, + "type": "array" + }, + "type": { + "description": "Specifies the type of GeoJSON object.", + "enum": [ + "MultiPoint" + ], + "type": "string" + } + }, + "type": "object" + }, + "GeoJSON.MultiPolygon": { + "description": "MultiPolygon geometry object.\nhttps://tools.ietf.org/html/rfc7946#section-3.1.7", + "properties": { + "bbox": { + "anyOf": [ + { + "additionalItems": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "minItems": 4, + "type": "array" + }, + { + "additionalItems": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "minItems": 6, + "type": "array" + } + ], + "description": "Bounding box of the coordinate range of the object's Geometries, Features, or Feature Collections.\nThe value of the bbox member is an array of length 2*n where n is the number of dimensions\nrepresented in the contained geometries, with all axes of the most southwesterly point\nfollowed by all axes of the more northeasterly point.\nThe axes order of a bbox follows the axes order of geometries.\nhttps://tools.ietf.org/html/rfc7946#section-5" + }, + "coordinates": { + "items": { + "items": { + "items": { + "items": { + "type": "number" + }, + "type": "array" + }, + "type": "array" + }, + "type": "array" + }, + "type": "array" + }, + "type": { + "description": "Specifies the type of GeoJSON object.", + "enum": [ + "MultiPolygon" + ], + "type": "string" + } + }, + "type": "object" + }, + "GeoJSON.Point": { + "description": "Point geometry object.\nhttps://tools.ietf.org/html/rfc7946#section-3.1.2", + "properties": { + "bbox": { + "anyOf": [ + { + "additionalItems": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "minItems": 4, + "type": "array" + }, + { + "additionalItems": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "minItems": 6, + "type": "array" + } + ], + "description": "Bounding box of the coordinate range of the object's Geometries, Features, or Feature Collections.\nThe value of the bbox member is an array of length 2*n where n is the number of dimensions\nrepresented in the contained geometries, with all axes of the most southwesterly point\nfollowed by all axes of the more northeasterly point.\nThe axes order of a bbox follows the axes order of geometries.\nhttps://tools.ietf.org/html/rfc7946#section-5" + }, + "coordinates": { + "description": "A Position is an array of coordinates.\nhttps://tools.ietf.org/html/rfc7946#section-3.1.1\nArray should contain between two and three elements.\nThe previous GeoJSON specification allowed more elements (e.g., which could be used to represent M values),\nbut the current specification only allows X, Y, and (optionally) Z to be defined.", + "items": { + "type": "number" + }, + "type": "array" + }, + "type": { + "description": "Specifies the type of GeoJSON object.", + "enum": [ + "Point" + ], + "type": "string" + } + }, + "type": "object" + }, + "GeoJSON.Polygon": { + "description": "Polygon geometry object.\nhttps://tools.ietf.org/html/rfc7946#section-3.1.6", + "properties": { + "bbox": { + "anyOf": [ + { + "additionalItems": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "minItems": 4, + "type": "array" + }, + { + "additionalItems": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "minItems": 6, + "type": "array" + } + ], + "description": "Bounding box of the coordinate range of the object's Geometries, Features, or Feature Collections.\nThe value of the bbox member is an array of length 2*n where n is the number of dimensions\nrepresented in the contained geometries, with all axes of the most southwesterly point\nfollowed by all axes of the more northeasterly point.\nThe axes order of a bbox follows the axes order of geometries.\nhttps://tools.ietf.org/html/rfc7946#section-5" + }, + "coordinates": { + "items": { + "items": { + "items": { + "type": "number" + }, + "type": "array" + }, + "type": "array" + }, + "type": "array" + }, + "type": { + "description": "Specifies the type of GeoJSON object.", + "enum": [ + "Polygon" + ], + "type": "string" + } + }, + "type": "object" + } + }, + "properties": { + "geography_id": { + "examples": [ + "3c9604d6-b5ee-11e8-96f8-529269fb1459" + ], + "format": "uuid", + "pattern": "^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$", + "type": "string" + }, + "geography_json": { + "$ref": "#/definitions/GeoJSON.FeatureCollection" + } + }, + "type": "object" +} diff --git a/policy/README.md b/policy/README.md index 012a4c92a..435a4633b 100644 --- a/policy/README.md +++ b/policy/README.md @@ -58,9 +58,9 @@ The machine-readable format allows Providers to obtain policies and compute comp Policies shall be published by regulatory bodies or their authorized delegates as JSON objects. These JSON objects shall be served by either [flat files](#flat-files) or via [REST API endpoints](#rest-endpoints). In either case, policy data shall follow the [schema](#schema) outlined below. -Policies typically refer to one or more associated geographies. Each policy and geography shall have a unique ID (UUID). +Policies typically refer to one or more associated geographies. Geographic information is obtained from the MDS Geography API. Each policy and geography shall have a unique ID (UUID). -Published policies and geographies should be treated as immutable data. Obsoleting or otherwise changing a policy is accomplished by publishing a new policy with a field named `prev_policies`, a list of UUID references to the policy or policies superseded by the new policy. +Published policies, like geographies, should be treated as immutable data. Obsoleting or otherwise changing a policy is accomplished by publishing a new policy with a field named `prev_policies`, a list of UUID references to the policy or policies superseded by the new policy. Geographical data shall be represented as GeoJSON `Feature` objects. No part of the geographical data should be outside the [municipality boundary][muni-boundary]. @@ -82,7 +82,7 @@ Among other use-cases, configuring a REST API allows an Agency to: 3) Adjust other attributes in closer to real time 4) Enumerate when policies are set to change -Responses must set the `Content-Type` header, as specified in the [Provider versioning][versioning] section. +Responses must set the `Content-Type` header, as specified in the [versioning][versioning] section. #### Responses and Error Messages