{"mock":"https://private-anon-21db62025d-openehr.apiary-mock.com/api/","production":"http://www.openehr.org/api/","proxy":"https://private-anon-21db62025d-openehr.apiary-proxy.com/api/"}
FORMAT: 1A HOST: http://www.openehr.org/api # OpenEHR EHR REST API (v0.1 proposal) **The following is a proposal for an OpenEHR EHR REST API. It is not complete and might still change completely before the final release.** The following specifications are not intended to describe an existing API but rather an abstract blueprint to which each openEHR implementation should adhere to. The openEHR EHR REST API enables interaction with an openEHR service in a RESTful manner. ## Considerations ### About `versionSelector` In many places parameter `versionSelector` is used to select a specific version (or associated data object) of a VERSIONED_OBJECT and can have the following values: - fixed string: `LATEST_TRUNK_VERSION` - a specific timestamp in the ISO8601 format (e.g. 2015-01-20T19:30:22.765+01:00) - a `versionUid` (VERSION unique identifier) - a `uid` (VERSIONED_OBJECT unique identifier) When the `versionSelector` parameter is not provided, the latest trunk version is returned, which is the same as specifying `versionSelector=LATEST_TRUNK_VERSION`. ## Glossary Throughout these specifications a set of short terms is being used as described below: | Term | Description | |------|-------------| |`ehrId`| The string value for an EHR identifier, stored under EHR.ehr_id.value, usually an UUID or GUID | |`uid`| The string value of a VERSIONED_OBJECT unique identifier, stored under VERSIONED_OBJECT.uid.value, e.g. 8849182c-82ad-4088-a07f-48ead4180515 | |`versionUid`| The string value of a VERSION unique identifier, stored under VERSION.uid.value, e.g. 8849182c-82ad-4088-a07f-48ead4180515::example.domain.com::1 | |`versionSelector`| The string value of a VERSION unique identifier, a specific timestamp or the string `LATEST_TRUNK_VERSION` | ## Data representation ### JSON Format - attribute names will be lowercase snake-case names as specified in the RM spec. For example: - context : {"start_time": "2016-01-01T00:00Z"} - metadata attributes (those that are not also RM attributes) will always be prefixed by a '_' - we will use a `_type` attribute to specify RM type which will be upper-case class name from the RM spec: { "_type": "DV_TEXT", "value": "Hello world!" } - null RM attributes will be absent when serialized as JSON ### Datetime format It is recommended to always use canonical ISO8601 expanded format, e.g. 2016-06-23T13:42:16.117+02:00, but any other valid ISO8601 datetime is accepted. Any datetime value provided by a create or update action will be preserved as it was sent (i.e. if composition was saved as narrow format, it will always return the way it was). # Group EHR ## EHR [/ehr] Management of EHR resources. ### Create a new EHR [POST /ehr{?subject_id,subject_namespace,subject_type}] Create a new `EHR` with an auto-generated identifier. Request body may contain `ehr_status` and `ehr_access` attributes. When provided these resources will also be created as part of the `create EHR` action, otherwise default resources will be created automatically by the service. + Request + Headers Prefer: return={representation|minimal} + Parameters + subject_id (HIER_OBJECT_ID, required) - id of the patient associated with the EHR (for EHR_STATUS.subject.external_ref.id) + subject_namespace (String, optional) - namespece of the type of the subject, if not specified, value is "DEMOGRAPHIC" + subject_type (String, optional) - type of subject, if not specified, value is "PERSON" + Body { "commit_audit": { "description": "Commit audit description", "committer": {"_type": "PARTY_IDENTIFIED", ... } }, "ehr_status": { /* not included attributes that are mandatory in the IM are set by the server, e.g. ehr_status.owner_id will be set when an uid is set for the EHR being created */ "_type": "VERSIONED_EHR_STATUS", "uid": "_a_valid_uid_", /* UUID or OID, UUID preferred */ "time_created": "YYYYMMDDThhmmss,SSS(Z|[+-]hhmm)", /* ISO8601 e.g. 20170801T010646,000+0000 or 20170801T010646,000Z */ } } + Response 201 (application/json) `201 Created` is returned when a new EHR has been successfully created. The EHR resource is returned in the body when the `Prefer` header has the value of `return=representation`. + Headers Location: /ehr/{ehrId} + Body { "system_id": {...}, "ehr_id": {...}, "ehr_status": "versioned ehr status uid", "ehr_access": "versioned ehr access uid", "directory": {}, "time_created", "..." } + Response 400 '400 Bad Request' is returned when unable to create a new EHR due to bad client Request, e.g. malformed syntax. + Body + Response 401 `401 Unauthorized` is returned when request is not authorised to be performed. + Body ### Create a new EHR with ehrId [PUT /ehr/{ehrId}] Create new `EHR` with the specified EHR identifier. The request body may contain `ehr_status` and `ehr_access` attributes, which will be used to create these initial resources associated with the new EHR. When the `ehr_status` or `ehr_access` attributes are not provided, defaults resources will be created by the service. + Parameters + ehrId (string) - EHR identifier + Request + Headers Prefer: return={representation|minimal} + Body { "commit_audit": { "description": "Commit audit description", "committer": {"_type": "PARTY_IDENTIFIED", ... } }, "ehr_status": {...}, "ehr_access": {...} } + Response 201 (application/json) `201 Created` is returned when a new EHR has been successfully created. The new EHR resource is returned in the body when the request's `Prefer` header value is `return=representation`. + Headers Location: /ehr/{ehrId} + Body { "system_id": {}, "ehr_id": {}, "ehr_status": "versioned ehr status uid", "ehr_access": "versioned ehr access uid", "directory": {}, "time_created", "..." } + Response 400 '400 Bad Request' is returned when unable to create a new EHR due to bad client Request, e.g. malformed syntax such as the 'ehrId' not a valid HIER_OBJECT_ID value. + Body + Response 409 Unable to create a new EHR due to a conflict with the current state of the resource. Can happen when the supplied ehrId already exists. // PP: ambiguous with 405 description. + Body + Response 401 `401 Unauthorized` is returned when request is not authorised to be performed. + Body + Response 405 `405 Method Not Allowed` is returned when an `EHR` with specified `ehrId` already exists. + Body ### Get EHR [GET /ehr/{ehrId}] Retrieve the EHR with the specified `ehrId`. + Parameters + ehrId (string) - EHR identifier + Response 200 (application/json) `200 OK` is returned when the EHR resource is successfully retrieved. + Body { "system_id": {}, "ehr_id": {}, "ehr_status": "versioned ehr status uid", "ehr_access": "versioned ehr access uid", "directory": {}, "time_created", "...", ... // to be defined, possibly counts of compositions, contributions, etc. } + Response 400 `400 Bad Request` is returned when the request has invalid content such as an invalid `ehrId` value. // PP: what is an invalid ehdId? are we validating format? not empty? it is better to make it opaque, if it comes and there is no EHR with that id, return 404. + Body + Response 401 `401 Unauthorized` is returned when request is not authorised. + Body + Response 404 `404 Not Found` is returned when an `EHR` with `ehrId` does not exist. + Body ### Delete EHR [DELETE /ehr/{ehrId}] _This call is under discussion._ // PP: do not allow DELETE, use PUT to update EHR_ACCESS to not queryable and/or not modifiable. Mark the `EHR` as deleted by updating the associated `EHR_STATUS` and `EHR_ACCESS` as deleted. The request body contains commit_audit attribute to be used as the commit audit details for the deleted `EHR_STATUS` and `EHR_ACCESS` resources. Where an implementation requires additional attestation to authorise the deletion, this can be provided in the attestations attribute in the request. Note: Some jurisdictions may require the service to physically delete the `EHR` and all its content. // PP: since this is a delicate operation, it might be performed by an EHR management system, IMO it is not needed at the API level (for now). This operation may be used to implement this capability but the commit_audit and attestations must be retained using an alternative audit trail than the usual contribution audit details. + Parameters + ehrId (string) - EHR identifier + Request { "commit_audit": { "description": "Commit audit description", "committer": { "_type": "PARTY_IDENTIFIED", ... } }, "attestations": { ... } } + Response 204 `204 No Content` is return when `EHR` is successfully deleted. + Body + Response 400 `400 Bad Request` is returned when the request has invalid content such as an invalid `ehrId` value. + Body + Response 401 `401 Unauthorized` is returned when request is not authorised. + Body + Response 404 `404 Not Found` is returned when an `EHR` with `ehrId` does not exist. + Body # Group EHR_STATUS ## EHR_STATUS [/ehr/{ehrId}/ehr_status] Management of EHR_STATUS resources. ### Get EHR_STATUS [GET /ehr/{ehrId}/ehr_status{?versionSelector}] Retrieve the `EHR_STATUS` associated with the EHR specified by `ehrId`. When the `versionSelector` parameter is provided, the `EHR_STATUS` version that existed at the specified version time is returned, otherwise the latest trunk version is returned. The `versionSelector` parameter may be an ISO8601 datetime string or symbolic value such as `LATEST_TRUNK_VERSION`. + Parameters + ehrId (string) - EHR identifier + versionSelector (string, optional) - version time specifier + Response 200 (application/json) `200 OK` is return with the EHR_STATUS resource in the body when it is successfully retrieved. + Headers Content-Location: /ehr/{ehrId}/ehr_status/{versionUid} ETag: {versionUid} + Body { "_type": "EHR_STATUS", "uid": "...", /* LOCATABLE */ "archetype_node_id": "", /* LOCATABLE */ "name": "", /* LOCATABLE */ "archetype_details": { /* LOCATABLE */ "archetype_id": "...", "rm_version": "1.0.3", }, "subject": { "external_ref": { "namespace": "DEMOGRAPHIC", "type": "PERSON", "id": { "_type": "HIER_OBJECT_ID", "value": "_valid_root_uid_::_extension_" /* root can be UUID or OID, UUID preferred '::_extension_' is optional */ } } } "is_queryable": true, "is_modifiable": true, "other_details": { /* optional, ITEM_STRUCTURE, archetypable */ "_type": "ITEM_TREE", "items": { ... } } } + Response 400 `400 Bad Request` is returned when the request has invalid content such as an invalid `ehrId` or `versionUid` format. + Body + Response 401 `401 Unauthorized` is returned when request is not authorised. + Body + Response 404 `404 Not Found` returned when `EHR` with `ehrId` does not exist or has been deleted or a version of an `EHR_STATUS` resource does not exist at the specified `versionSelector`. + Body ### Get EHR_STATUS by versionUid [GET /ehr/{ehrId}/ehr_status/{versionUid}] Retrieve the version of the `EHR_STATUS` associated with the specified `ehrId` and `versionUid`. // PP: this operation is included in the previous one, just use versionSelector=versionUid. IMO this should be removed. + Parameters + ehrId (string) - EHR identifier + versionUid (string) - version UID + Response 200 (application/json) `200 OK` is return when the `EHR_STATUS` is successfully retrieved. + Body { "_type": "EHR_STATUS", "uid": "...", /* LOCATABLE */ "archetype_node_id": "", /* LOCATABLE */ "name": "", /* LOCATABLE */ "archetype_details": { /* LOCATABLE */ "archetype_id": "...", "rm_version": "1.0.3", }, "subject": { "external_ref": { "namespace": "DEMOGRAPHIC", "type": "PERSON", "id": { "_type": "HIER_OBJECT_ID", "value": "_valid_root_uid_::_extension_" /* root can be UUID or OID, UUID preferred '::_extension_' is optional */ } } } "is_queryable": true, "is_modifiable": true, "other_details": { /* optional, ITEM_STRUCTURE, archetypable */ "_type": "ITEM_TREE", "items": { ... } } } + Response 400 `400 Bad Request` is returned when the request has invalid parameters such as an invalid ehrId value. + Body + Response 401 `401 Unauthorized` is returned when request is not authorised. + Body + Response 404 `404 Not Found` is returned when an `EHR` with `ehrId` does not exist or an `EHR_STATUS` with `versionUid` does not exist. + Body ### Update EHR_STATUS [PUT /ehr/{ehrId}/ehr_status] Update `EHR_STATUS` associated with the specified `ehrId`. The existing `versionUid` of `EHR_STATUS` resource must be specified in the `Match-If` header. The response will contain the updated `EHR_STATUS` resource when the `Prefer` header has a value of `return=representation` + Parameters + ehrId (string) - EHR identifier + Request (application/json) + Header Match-If: {precedingVersionUid} Prefer: return={representation|minimal} + Body { "_type": "EHR_STATUS", "uid": "...", /* LOCATABLE */ "archetype_node_id": "", /* LOCATABLE */ "name": "", /* LOCATABLE */ "archetype_details": { /* LOCATABLE */ "archetype_id": "...", "rm_version": "1.0.3", }, "subject": { "external_ref": { "namespace": "DEMOGRAPHIC", "type": "PERSON", "id": { "_type": "HIER_OBJECT_ID", "value": "_valid_root_uid_::_extension_" /* root can be UUID or OID, UUID preferred '::_extension_' is optional */ } } } "is_queryable": true, "is_modifiable": true, "other_details": { /* optional, ITEM_STRUCTURE, archetypable */ "_type": "ITEM_TREE", "items": { ... } } } + Response 200 `200 OK` return when `EHR_STATUS` resource is successfully updated. The updated `EHR_STATUS` resource is returned in the body when `prefer` header value is `return=representation`. + Headers Content-Location: /ehr/{ehrId}/ehr_status/{versionUid} ETag: {versionUid} + Body { "_type": "EHR_STATUS", "uid": "...", /* LOCATABLE */ "archetype_node_id": "", /* LOCATABLE */ "name": "", /* LOCATABLE */ "archetype_details": { /* LOCATABLE */ "archetype_id": "...", "rm_version": "1.0.3", }, "subject": { "external_ref": { "namespace": "DEMOGRAPHIC", "type": "PERSON", "id": { "_type": "HIER_OBJECT_ID", "value": "_valid_root_uid_::_extension_" /* root can be UUID or OID, UUID preferred '::_extension_' is optional */ } } } "is_queryable": true, "is_modifiable": true, "other_details": { /* optional, ITEM_STRUCTURE, archetypable */ "_type": "ITEM_TREE", "items": { ... } } } + Response 204 `204 No Content` is returned when `Prefer` header is NOT set to `return=representation`. + Headers Content-Location: /ehr/{ehrId}/ehr_status/{versionUid} ETag: {versionUid} + Response 400 `400 Bad Request` is returned when the request has invalid content such as an invalid `ehrId` format. + Body + Response 401 `401 Unauthorized` is returned when request is not authorised. + Body + Response 404 `404 Not Found` is returned when EHR with ehrId does not exist or has been deleted or a version of an `EHR_STATUS` resource does not exist at the specified `versionSelector`. + Body + Response 412 `412 Conflict` is return when `Match-If` header doesn't match the latest trunk version. Returns latest trunk version in the `Content-Location` and `ETag` headers. + Headers Content-Location: /ehr/{ehrId}/ehr_status/{versionUid} ETag: {versionUid} + Body ## VERSIONED_EHR_STATUS [/ehr/{ehrId}/versioned_ehr_status] Management of `VERSIONED_EHR_STATUS` resources. ### Get VERSIONED_EHR_STATUS [GET /ehr/{ehrId}/versioned_ehr_status] Retrieve `VERSIONED_EHR_STATUS` associated with an EHR specified by `ehrId` including its `revision_history`. + Parameters + ehrId (string) - EHR identifier + Response 200 (application/json) `200 OK` is return when the requested EHR's `VERSIONED_EHR_STATUS` is successfully retrieved, which is provided in the body. + Body { "_type": "VERSIONED_EHR_STATUS", "uid": "_a_valid_uid_", /* UUID or OID, UUID preferred */ "owner_id": "{ehrId}", "time_created": "DV_DATE_TIME", /* ISO8601 YYYYMMDDThhmmss,SSS(Z|[+-]hhmm) e.g. 20170801T010646,000+0000 or 20170801T010646,000Z */ "revision_history": { "items": [ { "version_id": "OBJECT_VERSION_ID", /* object_id::creating_system_id::version_tree_id */ "audits": [ { "system_id": "String", "time_committed": "DV_DATE_TIME", "change_type": { "value": "String", /* value from openehr terminoogy, change_type http://openehr.org/releases/1.0.2/architecture/terminology.pdf */ "defining_code": { "terminology_id": { "value": "openehr" }, "code_stirng": "String" } }, "desription": { "value": "String" } }, {...}, {...} ] }, {...}, {...} ] } } + Response 400 `400 Bad Request` is returned when the request is invalid such as an invalid `ehrId` value. + Body + Response 401 `401 Unauthorized` is returned when request is not authorised. + Body + Response 404 `404 Not Found` is returned when an `EHR` with `ehrId` does not exist. + Body ### Get EHR_STATUS version [GET /ehr/{ehrId}/versioned_ehr_status/version?{versionSelector}] Retrieve the `VERSION` of an `EHR_STATUS` associated with the specified `ehrId` and selected by `versionSelector`. When the `versionSelector` parameter is provided, the `VERSION` that existed at the specified version time is returned, otherwise the latest trunk version is returned. The `versionSelector` parameter may be an ISO8601 datetime string or symbolic value such as `LATEST_TRUNK_VERSION`. + Parameters + ehrId (string) - EHR identifier + versionSelector (string, optional) - version time specifier + Response 200 (application/json) `200 OK` is return when the requested `VERSION` is successfully retrieved, which is provided in the body. + Headers Content-Location: /ehr/{ehrId}/versioned_ehr_status/version/{versionUid} + Body { "_type": "ORIGINAL_VERSION", /* Use IMPORTED_VERSION if this is a copy from another server */ "uid": "OBJECT_VERSION_ID", /* _ehr_status_uid_::_system_id_::1 _system_id_ is the ID of the system from which the EHR was created */ "contribution": { /* does not include reference to other versions, even that is mandatory in the IM */ "uid": "HIER_OBJECT_ID", "audit": { "system_id": "String", "time_committed": "DV_DATE_TIME", "description": "String" /* optional */ } }, "signature": "String", /* optional */ "data": { "_type": "EHR_STATUS", "subject": { "external_ref": { "namespace": "DEMOGRAPHIC", "type": "PERSON", "id": { "_type": "HIER_OBJECT_ID", "value": "_valid_root_uid_::_extension_" /* root can be UUID or OID, UUID preferred '::_extension_' is optional */ } } } "is_queryable": true, "is_modifiable": true, "other_details": { /* optional, ITEM_STRUCTURE, archetypable */ "_type": "ITEM_TREE", "items": { ... } } }, "commit_audit": { /* the time committed attribute is set by the server */ "system_id": "_a_string_id_", /* same as the container version.uid.system_id */ "change_type": { "value": "creation", "terminology_id": { "value": "openehr" }, "code_string": "249" }, "description": "optional description" }, "attestations": [ { "system_id": "String", "time_committed": "DV_DATE_TIME", "description": "String" /* optional */ "reason": "DV_TEXT", "proof": "String", /* optional */ "is_pending": "Boolean" }, {...}, {...} ] } + Response 400 `400 Bad Request` is returned when the request is invalid such as an invalid `ehrId` or `versionSelector` value. + Body + Response 401 `401 Unauthorized` is returned when request is not authorised. + Body + Response 404 `404 Not Found` is returned when `EHR` with `ehrId` does not exist, deleted or when `EHR_STATUS` does not exist at the specified `versionSelector`. + Body ### Get EHR_STATUS version by uid [GET /ehr/{ehrId}/versioned_ehr_status/version/{versionUid}] Retrieve `VERSION` of an `EHR_STATUS` associated with the specified `ehrId` and `versionUid`. + Parameters + ehrId (string) - EHR identifier + versionUid (string) - version uid + Response 200 (application/json) `200 OK` is return when the requested `VERSION` is successfully retrieved. + Body { "_type": "ORIGINAL_VERSION", /* Use IMPORTED_VERSION if this is a copy from another server */ "uid": "OBJECT_VERSION_ID", /* _ehr_status_uid_::_system_id_::1 _system_id_ is the ID of the system from which the EHR was created */ "contribution": { /* does not include reference to other versions, even that is mandatory in the IM */ "uid": "HIER_OBJECT_ID", "audit": { "system_id": "String", "time_committed": "DV_DATE_TIME", "description": "String" /* optional */ } }, "signature": "String", /* optional */ "data": { "_type": "EHR_STATUS", "subject": { "external_ref": { "namespace": "DEMOGRAPHIC", "type": "PERSON", "id": { "_type": "HIER_OBJECT_ID", "value": "_valid_root_uid_::_extension_" /* root can be UUID or OID, UUID preferred '::_extension_' is optional */ } } } "is_queryable": true, "is_modifiable": true, "other_details": { /* optional, ITEM_STRUCTURE, archetypable */ "_type": "ITEM_TREE", "items": { ... } } }, "commit_audit": { /* the time committed attribute is set by the server */ "system_id": "_a_string_id_", /* same as the container version.uid.system_id */ "change_type": { "value": "creation", "terminology_id": { "value": "openehr" }, "code_string": "249" }, "description": "optional description" }, "attestations": [ { "system_id": "String", "time_committed": "DV_DATE_TIME", "description": "String" /* optional */ "reason": "DV_TEXT", "proof": "String", /* optional */ "is_pending": "Boolean" }, {...}, {...} ] } + Response 400 `400 Bad Request` is returned when the request is invalid such as an invalid `ehrId` or `versionUid` format. + Body + Response 401 `401 Unauthorized` is returned when request is not authorised. + Body + Response 404 `404 Not Found` is returned when an `EHR` with `ehrId` does not exist or `EHR_STATUS` with `versionUid` does not exist. + Body # Group EHR_ACCESS ## EHR_ACCESS [/ehr/{ehrId}/ehr_access] ### Get EHR_ACCESS by versionUid [GET /ehr/{ehrId}/ehr_access/{versionUid}] + Parameters + ehrId (string) - EHR identifier + versionUid (string) - version unique identifier + Response 200 (application/json) `200 OK` is returned when the EHR_ACCESS is successfully retrieved. + Body { "uid": "...", "settings": {} } + Response 401 `401 Unauthorized` is returned when request is not authorised. + Body + Response 404 `404 Not Found` is returned when an `EHR` with `ehrId` does not exist or an `EHR_STATUS` with `versionUid` does not exist. + Body ### Get EHR_ACCESS [GET /ehr/{ehrId}/ehr_access{?versionSelector}] + Parameters + ehrId (string) - EHR id + versionSelector (string, optional) - version time specifier + Response 200 (application/json) + Headers Content-Location: /ehr/{ehrId}/ehr_access/{versionUid} ETag: {versionUid} + Body { "uid": "...", "settings": {} } + Response 401 Unauthorized. + Body + Response 404 No EHR with the given id. + Body ### Update an EHR_ACCESS [PUT /ehr/{ehrId}/ehr_access] + Parameters + ehrId (string) - EHR id + Request (application/json) + Header Match-If: {precedingVersionUid} Prefer: return={representation/minimal} + Body { "settings": {} } + Response 200 Returned when `Prefer` header is set to `return=representation`. + Headers Content-Location: /ehr/{ehrId}/ehr_status/{versionUid} ETag: {versionUid} + Body { "uid": "...", "settings": {} } + Response 204 Returned when `Prefer` header is NOT set to `return=representation`. + Headers Content-Location: /ehr/{ehrId}/ehr_access/{versionUid} ETag: {versionUid} + Response 401 Unauthorized. + Body + Response 404 No EHR with the given id. + Body + Response 412 `Match-If` header doesn't match the last version. Returns last version in the `Content-Location` and `ETag` headers. + Headers Content-Location: /ehr/{ehrId}/ehr_access/{versionUid} ETag: {versionUid} + Body ## VERSIONED_EHR_ACCESS [/ehr/{ehrId}/versioned_ehr_access] ### Get a VERSIONED_EHR_ACCESS [GET /ehr/{ehrId}/versioned_ehr_access] + Parameters + ehrId (string) - EHR id + Response 200 (application/json) + Body { "uid": "xxx", "owner_id": "{ehrId}", "time_created": "ISO8601 timestamp", "version_count: 12, "all_version_ids": [ "versioned_uid1", "versioned_uid2", ... ] } + Response 401 Unauthorized. + Body + Response 404 No EHR with the given id. + Body ### Get an EHR_ACCESS version by versionUid [GET /ehr/{ehrId}/versioned_ehr_access/versions/{versionUid}] + Parameters + ehrId (string) - EHR id + versionUid (string) - version UID + Response 200 (application/json) + Body { "contribution": {}, "signature": "...", "commit_audit": {}, "uid": "...", "data": { "settings": {}, } } + Response 401 Unauthorized. + Body + Response 404 No EHR with the given id. + Body ### Get an EHR_ACCESS version [GET /ehr/{ehrId}/versioned_ehr_access/version{?versionSelector}] + Parameters + ehrId (string) - EHR id + versionSelector (string, optional) - version time specifier + Response 200 (application/json) + Body { "contribution": {}, "signature": "...", "commit_audit": {}, "uid": "...", "data": { "settings": {}, } } + Response 204 No VERSION at versionSelector. + Body + Response 401 Unauthorized. + Body + Response 404 No EHR with the given id. + Body ### Create a new EHR_ACCESS version [POST /ehr/{ehrId}/versioned_ehr_access/version] + Parameters + ehrId (string) - EHR id + Request + Body (application/json) { "commit_audit": {}, "data": { "settings": {}, } } + Headers Match-If: {precedingVersionUid} Prefer: return={representation/minimal} + Response 201 (application/json) New EHR_ACCESS version was created. Content body is only returned when `Prefer` header was set to `return=representation` otherwise only headers are returned. + Headers Location: /ehr/{ehrId}/versioned_ehr_access/versions/{versionUid} ETag: {versionUid} + Body { "uid": "...", "contribution": {}, "signature": "...", "commit_audit": {}, "data": { "subject": {}, "is_modifiable": "...", "is_queryable": "...", "other_details": {} } } + Response 401 Unauthorized. + Body + Response 404 No EHR with given id. + Body + Response 412 `Match-If` header doesn't match the last version. Returns last version in the `Content-Location` and `ETag` headers. + Headers Content-Location: /ehr/{ehrId}/versioned_ehr_access/versions/{versionUid} ETag: {versionUid} + Body # Group DIRECTORY ## Directory [/ehr/{ehrId}/directory] ### Create a directory [POST /ehr/{ehrId}/directory] + Parameters + ehrId (string) - EHR id + Request + Body (application/json) { "items": [...], "folders": [{}] } + Headers Prefer: return={representation/minimal} + Response 201 (application/json) New directory was created. Content body is only returned when `Prefer` header has `return=representation` otherwise only headers are returned. + Headers Location: /ehr/{ehrId}/directory/{versionUid} ETag: {versionUid} + Body { "uid": "...", "items": [...], "folders": [{}] } + Response 400 Bad request - error creating a directory. + Body + Response 401 Unauthorized. + Body + Response 404 No EHR with the given id. + Body ### Update a directory [PUT /ehr/{ehrId}/directory] + Parameters + ehrId (string) - EHR id + Request + Body (application/json) { "items": [...], "folders": [{}] } + Headers Match-If: {precedingVersionUid} Prefer: return={representation/minimal} + Response 200 (application/json) Directory was updated. Returned when `Prefer` header is set to `return=representation`. + Headers Location: /ehr/{ehrId}/directory/{versionUid} ETag: {versionUid} + Body { "uid": "...", "items": [...], "folders": [{}] } + Response 204 Directory was updated. Returned when `Prefer` header is NOT set to `return=representation`. + Headers Location: /ehr/{ehrId}/directory/{versionUid} ETag: {versionUid} + Response 400 Bad request - error when updating a directory. + Body + Response 401 Unauthorized. + Body + Response 404 No EHR with the given id. + Body + Response 412 `Match-If` header doesn't match the last version. Returns last version in the `Content-Location` and `ETag` headers. + Headers Content-Location: /ehr/{ehrId}/directory/{versionUid} ETag: {versionUid} + Body ### Delete a directory [DELETE /ehr/{ehrId}/directory] + Parameters + ehrId (string) - EHR id + Request + Headers Match-If: {precedingVersionUid} + Response 204 Directory was deleted. + Body + Response 400 Bad request - error deleting directory. + Body + Response 401 Unauthorized. + Body + Response 404 No EHR with the given id. + Body + Response 412 `Match-If` header doesn't match the last version. Returns last version in the `Content-Location` and `ETag` headers. + Headers Content-Location: /ehr/{ehrId}/directory/{versionUid} ETag: {versionUid} + Body ### Get a directory or its sub-folder by versionUid [GET /ehr/{ehrId}/directory/{versionUid}{?path}] + Parameters + ehrId (string) - EHR id + versionUid (string) - version UID + path (string, optional) - path to a sub-folder + Response 200 (application/json) + Body { "uid": "...", "items": [...], "folders": [{}] } + Response 204 No sub-folder at provided path. + Body + Response 401 Unauthorized. + Body + Response 404 No EHR with the given id or no directory with specified versionUid. + Body ### Get a directory or its sub-folder [GET /ehr/{ehrId}/directory{?versionSelector,path}] + Parameters + ehrId (string) - EHR id + versionSelector (string, optional) - version time specifier + path (string, optional) - path to a sub-folder + Response 200 (application/json) + Headers Location: /ehr/{ehrId}/directory/{versionUid} ETag: {versionUid} + Body { "uid": "...", "items": [...], "folders": [{}] } + Response 204 EHR has no directory at versionSelector or no sub-folder at provided path. + Body + Response 401 Unauthorized. + Body + Response 404 No EHR with the given id. + Body # Group COMPOSITION ## Composition [/ehr/{ehrId}/compositions] ### Get a composition by version uid [GET /ehr/{ehrId}/compositions/{versionUid}{?format}] // PP: IMO this should redirect to GET /compositions/versionUid, or just use that one and remove this one. + Parameters + ehrId (string) - EHR id. + versionUid (string) - version UID + format (string, optional)...format of the composition (when ommitted canonical openEHR is assumed) + Response 200 (application/json) + Body { "_type": "COMPOSITION", "name": { "_type": "DV_TEXT", "value": "Vital Signs" }, ... } + Response 401 Unauthorized. + Body + Response 404 No EHR or no composition with the version uid. + Body ### Get a composition [GET /ehr/{ehrId}/compositions/{object_id}{?versionSelector,format}] // PP: IMO this should redirect to GET /compositions/objectId, or just use that one and remove this one. + Parameters + ehrId (string) - EHR id + object_id (string) - VERSIONED COMPOSITION's uid + versionSelector (string, optional) - version time specifier + format (string, optional)...format of the composition (when ommitted canonical openEHR is assumed) + Response 200 (application/json) + Headers Content-Location: /ehr/{ehrId}/compositions/{versionUid} ETag: {versionUid} + Body { "_type": "COMPOSITION", "name": { "_type": "DV_TEXT", "value": "Vital Signs" }, ... } + Response 204 (application/json) No composition at specified versionSelector. + Body + Response 401 Unauthorized. + Body + Response 404 No EHR or no composition with the given object id. + Body ### Create a new composition [POST /ehr/{ehrId}/compositions{?format}] // PP: why not POST /compositions with ehrId as param? we can keep all the COMPOSITION endpoints under /compositions instead of using both /ehr/ehrId/compositions and /compositions, IMO is simpler to implement with one set of URLs for a resource. Maybe someone have a good argument for keeping both endpoints. + Parameters + ehrId (string) - EHR id + format (string, optional)...format of the composition (when omitted canonical openEHR is assumed) + Request + Body (application/json) { "_type": "COMPOSITION", "name": { "_type": "DV_TEXT", "value": "Vital Signs" }, ... } + Headers Prefer: return={representation/minimal} + Response 201 New composition was created. Content body is only returned when `Prefer` header has `return=representation` otherwise only headers are returned. + Headers Location: /ehr/{ehrId}/compositions/{versionUid} ETag: {versionUid} + Body { "_type": "COMPOSITION", "name": { "_type": "DV_TEXT", "value": "Vital Signs" }, ... } + Response 400 Bad request: composition validation errors. + Body { "message": "Error message", "validationErrors": [ "error1", "error2" ] } + Response 401 Unauthorized. + Body + Response 404 No EHR with the given id. + Body ### Update or create a composition [PUT /ehr/{ehrId}/compositions/{object_id}{?format}] This call can be used to update an existing composition (identified by {objectId}) or to create a new one with the supplied {objectId} instead of a server assigned one. In case of an update `Match-If` header _might_ be required. + Parameters + ehrId (string) - EHR id + object_id (string) - object id of the composition to update or create with this id + format (string, optional) - optional format of the composition (when ommitted canonical openEHR is assumed) + Request + Body (application/json) { "_type": "COMPOSITION", "name": { "_type": "DV_TEXT", "value": "Vital Signs" }, ... } + Headers Match-If: {precedingVersionUid} Prefer: return={representation/minimal} + Response 200 (application/json) Returned when `Prefer` header is set to `return=representation`. + Headers Content-Location: /ehr/{ehrId}/compositions/{versionUid} ETag: {versionUid} + Body { "_type": "COMPOSITION", "name": { "_type": "DV_TEXT", "value": "Vital Signs" }, ... } + Response 204 Returned when `Prefer` header is NOT set to `return=representation`. + Headers Content-Location: /ehr/{ehrId}/compositions/{versionUid} ETag: {versionUid} + Response 400 Bad request: composition validation errors. + Body { "message": "Error message", "validationErrors": [ "error1", "error2" ] } + Response 401 Unauthorized. + Body + Response 404 No EHR with the given id or no composition with the given object id. + Body + Response 412 `Match-If` header doesn't match the last version. Returns last version in the `Content-Location` and `ETag` headers. + Headers Content-Location: /ehr/{ehrId}/ehr_status/{versionUid} ETag: {versionUid} + Body ### Delete a composition [DELETE /ehr/{ehrId}/compositions/{object_id}] + Parameters + ehrId (string) - EHR id + object_id (string) - object id of the composition to delete + Request + Headers Match-If: {precedingVersionUid} + Response 204 Composition was deleted. + Headers Content-Location: /ehr/{ehrId}/compositions/{versionUid} ETag: {versionUid} + Body + Response 400 Bad request. + Body + Response 401 Unauthorized. + Body + Response 404 No EHR with the given id or no composition with the given object id. + Body + Response 412 `Match-If` header doesn't match the last version. Returns last version in the `Content-Location` and `ETag` headers. + Headers Content-Location: /ehr/{ehrId}/compositions/{versionUid} ETag: {versionUid} + Body ### Update a composition directly [PUT /compositions/{objectId}{?format}] + Parameters + objectId (string) - object id of the composition to update + format (string, optional) - optional format of the composition (when omitted canonical openEHR is assumed) + Request + Body (application/json) { "_type": "COMPOSITION", "name": { "_type": "DV_TEXT", "value": "Vital Signs" }, ... } + Headers Match-If: {precedingVersionUid} Prefer: return={representation/minimal} + Response 200 (application/json) Returned when `Prefer` header is set to `return=representation`. + Headers Content-Location: /ehr/{ehrId}/compositions/{versionUid} ETag: {versionUid} + Body { "_type": "COMPOSITION", "name": { "_type": "DV_TEXT", "value": "Vital Signs" }, ... } + Response 204 Returned when `Prefer` header is NOT set to `return=representation`. + Headers Content-Location: /ehr/{ehrId}/compositions/{versionUid} ETag: {versionUid} + Response 400 (application/json) Bad request: composition validation errors. + Body { "message": "Error message", "validationErrors": [ "error1", "error2" ] } + Response 401 Unauthorized. + Body + Response 404 No EHR with the given id or no composition with the given object id. + Body + Response 412 `Match-If` header doesn't match the last version. Returns last version in the `Content-Location` and `ETag` headers. + Headers Content-Location: /ehr/{ehrId}/ehr_status/{versionUid} ETag: {versionUid} + Body ### Delete a composition directly [DELETE /compositions/{objectId}] + Parameters + objectId (string) - object id of the composition to delete + Request + Headers Match-If: {precedingVersionUid} + Response 204 Composition was deleted. + Headers Content-Location: /compositions/{versionUid} ETag: {versionUid} + Body + Response 400 Bad request. + Body + Response 401 Unauthorized. + Body + Response 404 No EHR with the given id or no composition with the given object id. + Body + Response 412 `Match-If` header doesn't match the last version. Returns last version in the `Content-Location` and `ETag` headers. + Headers Content-Location: /compositions/{versionUid} ETag: {versionUid} + Body ### Get a composition by version uid directly [GET /compositions/{versionUid}{?format}] + Parameters + versionUid (string) - version uid + format (string, optional)...format of the composition (when omitted canonical openEHR is assumed) + Response 200 (application/json) + Body { "_type": "COMPOSITION", "name": { "_type": "DV_TEXT", "value": "Vital Signs" }, ... } + Response 401 Unauthorized. + Body + Response 404 No composition with the version uid. + Body ### Get a composition directly [GET /compositions/{objectId}{?versionSelector,format}] + Parameters + objectId (string) - VERSIONED_COMPOSITION's uid + versionSelector (string, optional) - version time specifier + format (string, optional)...format of the composition (when omitted canonical openEHR is assumed) + Response 200 (application/json) + Headers Content-Location: /compositions/{versionUid} ETag: {versionUid} + Body { "_type": "COMPOSITION", "name": { "_type": "DV_TEXT", "value": "Vital Signs" }, ... } + Response 204 (application/json) No composition at specified versionSelector. + Body + Response 401 Unauthorized. + Body + Response 404 No composition with the given object id. + Body ## Versioned Composition [/ehr/{ehrId}/versioned_compositions] ### Create a new versioned composition [POST /ehr/{ehrId}/versioned_compositions] + Parameters + ehrId (string) - EHR id + Request + Headers Prefer: return={representation/minimal} + Response 201 (application/json) New versioned composition was created. Content body is only returned when `Prefer` header has `return=representation` otherwise only headers are returned. + Headers Location: /ehr/{ehrId}/versioned_compositions/{uid} + Body { "uid": "xxx", "owner_id": "{ehrId}", "time_created": "ISO8601 timestamp" } + Response 400 Bad request - when VERSIONED_COMPOSITION with the given uid already exists. + Body + Response 401 Unauthorized. + Body + Response 404 No EHR with the given id. + Body ### Create a new versioned composition with supplied uid [PUT /ehr/{ehrId}/versioned_compositions/{uid}] + Parameters + ehrId (string) - EHR id + uid (string) - VERSIONED_COMPOSITION uid + Request + Headers Prefer: return={representation/minimal} + Response 201 (application/json) New versioned composition was created. Content body is only returned when `Prefer` header has `return=representation` otherwise only headers are returned. + Headers Location: /ehr/{ehrId}/versioned_compositions/{uid} + Body { "uid": "xxx", "owner_id": "{ehrId}", "time_created": "ISO8601 timestamp" } + Response 400 Bad request - when VERSIONED_COMPOSITION with the given uid already exists. + Body + Response 401 Unauthorized. + Body + Response 404 No EHR with the given id. + Body ### Get a versioned composition [GET /ehr/{ehrId}/versioned_compositions/{uid}] Gets a complete VERSIONED_COMPOSITION. + Parameters + ehrId (string) - EHR id + uid (string) - VERSIONED_COMPOSITION's uid + Response 200 (application/json) + Headers Location: /ehr/{ehrId}/versioned_compositions/{uid} + Body { "uid": "xxx", "owner_id": "{ehrId}", "time_created": "ISO8601 timestamp", "version_count: 12, "all_version_ids": [ "versioned_uid1", "versioned_uid2", ... ] } + Response 400 Bad request - when VERSIONED_COMPOSITION with the given uid already exists. + Body + Response 401 Unauthorized. + Body + Response 404 No EHR with the given id. + Body ### Create a new composition version [POST /ehr/{ehrId}/versioned_compositions/{uid}/version{?format}] + Parameters + ehrId (string) - EHR id + uid (string) - VERSIONED_COMPOSITION's uid + format (string, optional) - optional format of the composition (when omitted canonical openEHR is assumed) + Request + Body (application/json) { "commit_audit": {}, "data": { "_type": "COMPOSITION", "name": { "_type": "DV_TEXT", "value": "Vital Signs" } ... } } + Headers Match-If: {precedingVersionUid} Prefer: return={representation/minimal} + Response 201 (application/json) New composition version was created. Content body is only returned when `Prefer` header was set to `return=representation` otherwise only headers are returned. + Headers Location: /ehr/{ehrId}/versioned_compositions/{uid}/versions/{versionUid} ETag: {versionUid} + Body { "contribution": {}, "signature": "...", "commit_audit": {}, "uid": "...", "data": { "_type": "COMPOSITION", "name": { "_type": "DV_TEXT", "value": "Vital Signs" } ... } } + Response 400 Bad request: composition validation errors. + Body { "message": "Error message", "validationErrors": [ "error1", "error2" ] } + Response 401 Unauthorized. + Body + Response 404 No EHR with the given id or no VERSIONED_COMPOSITION with uid. + Body + Response 412 `Match-If` header doesn't match the last version. Returns last version in the `Content-Location` and `ETag` headers. + Headers Content-Location: /ehr/{ehrId}/versioned_compositions/{uid}/versions/{versionUid} ETag: {versionUid} + Body ### Get a composition version by versionUid [GET /ehr/{ehrId}/versioned_compositions/{uid}/version/{versionUid}{?format}] + Parameters + ehrId (string) - EHR id + uid (string) - VERSIONED_COMPOSITION's uid + versionUid (string) - version uid + format (string, optional) - optional format of the composition (when ommitted canonical openEHR is assumed) + Response 200 (application/json) + Body { "contribution": {}, "signature": "...", "commit_audit": {}, "uid": "...", "data": { "_type": "COMPOSITION", "name": { "_type": "DV_TEXT", "value": "Vital Signs" } ... } } + Response 401 Unauthorized. + Body + Response 404 No EHR with the given id, no VERSIONED_COMPOSITION with uid or no version with versionUid. + Body ### Get a composition version [GET /ehr/{ehrId}/versioned_compositions/{uid}/version{?versionSelector,format}] + Parameters + ehrId (string) - EHR id + uid (string) - VERSIONED_COMPOSITION's uid + versionSelector (string, optional) - version time specifier + format (string, optional) - optional format of the composition (when omitted canonical openEHR is assumed) + Response 200 (application/json) + Headers Location: /ehr/{ehrId}/versioned_compositions/{uid}/versions/{versionUid} ETag: {versionUid} + Body { "contribution": {}, "signature": "...", "commit_audit": {}, "uid": "...", "data": { "_type": "COMPOSITION", "name": { "_type": "DV_TEXT", "value": "Vital Signs" } ... } } + Response 401 Unauthorized. + Body + Response 404 No EHR with the given id, no VERSIONED_COMPOSITION with uid or no version with versionUid. + Body # Group QUERY ## Querying [/query] ### Get AQL query results [GET /query/?aql={aql}] Execute an AQL query as given by the aql parameter. ```sql select a_a/data[at0002]/events[at0003]/time as When, a_a/data[at0002]/events[at0003]/data[at0001]/items[at0004]/value as Temperature from EHR e contains COMPOSITION a CONTAINS OBSERVATION a_a[openEHR-EHR-OBSERVATION.body_temperature.v1] order by a_a/data[at0002]/events[at0003]/time desc offset 0 limit 2 ``` + Parameters + aql - The aql to be executed + Response 200 (application/json) { "_type": "RESULTSET", "@schemaversion": "0.1.0", "_type": "raw", "@created": "2016-06-22T07:54:04.758+02:00", "@generator": "<The resultset generator>", "totalResults": 2, "columns": [ { "name": "When", "path": "/data[at0002]/events[at0003]/time" }, { "name": "Temperature", "path": "/data[at0002]/events[at0003]/data[at0001]/items[at0004]/value" } ], "rows": [ [ { "_type": "DV_DATE_TIME", "value": "2016-06-08T11:02:47+02:00" }, { "_type": "DV_QUANTITY", "magnitude": 38.0, "units": "?C" } ], [ { "_type": "DV_DATE_TIME", "value": "2016-06-05T08:53:36+02:00" }, { "_type": "DV_QUANTITY", "magnitude": 37.0, "units": "Cel" } ] ] } ### Get query results [POST /query/aql] Execute an AQL query. NOTE: we might add a header to indicate which EHR to execute against to allow systems that need to route based of EHR id to do so without having to analyze the request body. + Request (application/json) + Body { "aql": "SELECT ....", "aqlParameters": { "parameter-name": "parameter-value",... }, "offset": 999, "fetch": 888, // possibly more, TBD } + Response 200 { "metaData": { "hits": 199, ... }, "resultSet": [ { "unit": "?C", "temperature": 38.8 }, { "unit": "?C", "temperature": 38.8 }, { "unit": "?C", "temperature": 38.8 } ], "executedAql": "aql with replaced parameters", }