Dear community,
We are currently working on a TypeScript SDK that should abstract over differences between openEHR CDR vendors. While implementing the Create CONTRIBUTION endpoint, we ran into a mismatch where we are no longer sure what the ground truth should be: the REST specification, the OpenAPI schema, the examples, or the behavior of existing CDRs.
Context
The Create CONTRIBUTION endpoint describes the request body as a relaxed CONTRIBUTION with:
versions: array ofUPDATE_VERSIONaudit:UPDATE_AUDIT
Each UPDATE_VERSION also has commit_audit, again typed as UPDATE_AUDIT.
The Platform Service Model defines UPDATE_AUDIT as the client-provided audit object used by the server to create an AUDIT_DETAILS object. In that model, UPDATE_AUDIT.change_type is a Terminology_code.
However, the RM AUDIT_DETAILS class has change_type: DV_CODED_TEXT.
That conceptual distinction makes sense: UPDATE_AUDIT is the input DTO, while AUDIT_DETAILS is the persisted RM object created by the server. The problem is that the JSON shape expected in practice does not seem to follow the UPDATE_AUDIT schema consistently.
What we see in the official OpenAPI schema
In the validation OpenAPI schema, UpdateAudit.change_type references TerminologyCode:
UpdateAudit:
title: UPDATE_AUDIT
required:
- change_type
- committer
type: object
properties:
_type:
type: string
default: UPDATE_AUDIT
change_type:
$ref: '#/components/schemas/TerminologyCode'
description:
$ref: '#/components/schemas/UDvText'
committer:
$ref: '#/components/schemas/UPartyProxy'
description: The set of attributes required to document the committal of an information item to a repository. Used by the server to create an AUDIT_DETAILS object.
example:
change_type:
value: creation
defining_code:
terminology_id: openehr
code_string: '249'
description: Description text
committer:
_type: PARTY_IDENTIFIED
name: A user name
So the schema says TerminologyCode, but the example uses a DV_CODED_TEXT-like shape (value + defining_code).
What vendors accept
We tested with:
- Better EHR Server 4.7.8
- EHRbase CDR 2.31.0
Both reject a TerminologyCode-shaped change_type and expect a DV_CODED_TEXT-shaped change_type instead.
Better EHR Server 4.7.8
Better accepts change_type as DV_CODED_TEXT, with _type: "UPDATE_AUDIT":
{
"versions": [
{
"data": "<Composition>",
"lifecycle_state": {
"value": "complete",
"defining_code": {
"terminology_id": { "value": "openehr" },
"code_string": "532"
}
},
"commit_audit": {
"_type": "UPDATE_AUDIT",
"system_id": "integration-test-system",
"change_type": {
"value": "creation",
"defining_code": {
"terminology_id": { "value": "openehr" },
"code_string": "249"
}
},
"committer": {
"_type": "PARTY_IDENTIFIED",
"name": "integration-test-committer"
}
}
}
],
"audit": {
"_type": "UPDATE_AUDIT",
"system_id": "integration-test-system",
"change_type": {
"value": "creation",
"defining_code": {
"terminology_id": { "value": "openehr" },
"code_string": "249"
}
},
"committer": {
"_type": "PARTY_IDENTIFIED",
"name": "integration-test-committer"
}
}
}
EHRbase CDR 2.31.0
EHRbase accepts change_type as DV_CODED_TEXT, but with _type: "AUDIT_DETAILS" rather than _type: "UPDATE_AUDIT":
{
"versions": [
{
"data": "<Composition>",
"lifecycle_state": {
"value": "complete",
"defining_code": {
"terminology_id": { "value": "openehr" },
"code_string": "532"
}
},
"commit_audit": {
"_type": "AUDIT_DETAILS",
"system_id": "integration-test-system",
"change_type": {
"value": "creation",
"defining_code": {
"terminology_id": { "value": "openehr" },
"code_string": "249"
}
},
"committer": {
"_type": "PARTY_IDENTIFIED",
"name": "integration-test-committer"
}
}
}
],
"audit": {
"_type": "AUDIT_DETAILS",
"system_id": "integration-test-system",
"change_type": {
"value": "creation",
"defining_code": {
"terminology_id": { "value": "openehr" },
"code_string": "249"
}
},
"committer": {
"_type": "PARTY_IDENTIFIED",
"name": "integration-test-committer"
}
}
}
What appears spec-compliant but is rejected
Based on the OpenAPI UpdateAudit.change_type -> TerminologyCode schema, we expected this shape to be valid:
{
"versions": [
{
"data": "<Composition>",
"lifecycle_state": {
"value": "complete",
"defining_code": {
"terminology_id": { "value": "openehr" },
"code_string": "532"
}
},
"commit_audit": {
"_type": "UPDATE_AUDIT",
"system_id": "integration-test-system",
"change_type": {
"terminology_id": "openehr",
"code_string": "249"
},
"committer": {
"_type": "PARTY_IDENTIFIED",
"name": "integration-test-committer"
}
}
}
],
"audit": {
"_type": "UPDATE_AUDIT",
"system_id": "integration-test-system",
"change_type": {
"terminology_id": "openehr",
"code_string": "249"
},
"committer": {
"_type": "PARTY_IDENTIFIED",
"name": "integration-test-committer"
}
}
}
EHRbase rejects this with validation errors indicating it expected DV_CODED_TEXT fields (value and defining_code) under change_type. Better also rejects it.
Questions
- For the REST
Create CONTRIBUTIONrequest body, shouldauditandversions[].commit_auditbe serialized asUPDATE_AUDITor asAUDIT_DETAILS? - Should
UPDATE_AUDIT.change_typebe serialized asTerminologyCode/TERMINOLOGY_CODE, or asDV_CODED_TEXT? - Is the OpenAPI schema wrong, the example wrong, or are we misunderstanding how
Terminology_codein the Service Model should be represented in canonical JSON? - Should implementations accept
_type: "UPDATE_AUDIT",_type: "AUDIT_DETAILS", both, or should_typebe omitted for this DTO? - For SDK authors, what should be treated as the ground truth: the Platform Service Model, the REST OpenAPI schema, the REST examples, or the common behavior of current CDRs?
Our practical concern is that we need to generate stable TypeScript types and runtime serializers. At the moment, it looks like the most interoperable SDK behavior would be vendor-specific serialization profiles:
- Better:
UPDATE_AUDITwithDV_CODED_TEXT-shapedchange_type - EHRbase:
AUDIT_DETAILSwithDV_CODED_TEXT-shapedchange_type
But before encoding that into the SDK, we would like to know whether there is a normative answer we are missing.
Thanks in advance for any clarification.
