Round-Trip JSON

This guide demonstrates a full serialise → deserialise round-trip using Clarotech.OpenEHR.RM.Json. It continues from the Building a Composition guide.

Setup

dotnet add package Clarotech.OpenEHR.RM.Json
using Clarotech.OpenEHR.RM.Json;

1 — Serialise to Canonical JSON

// Assume `composition` was built as shown in the Building a Composition guide.

// Compact JSON (for storage/transport)
string json = OpenEhrJsonSerializer.Serialize(composition);

// Pretty-printed (for debugging / display)
string pretty = OpenEhrJsonSerializer.Serialize(composition, writeIndented: true);

Console.WriteLine(pretty);

Abbreviated output:

{
  "_type": "COMPOSITION",
  "name": { "_type": "DV_TEXT", "value": "Vital Signs" },
  "archetype_node_id": "openEHR-EHR-COMPOSITION.encounter.v1",
  "language": {
    "_type": "CODE_PHRASE",
    "terminology_id": { "_type": "TERMINOLOGY_ID", "value": "ISO_639-1" },
    "code_string": "en"
  },
  "territory": {
    "_type": "CODE_PHRASE",
    "terminology_id": { "_type": "TERMINOLOGY_ID", "value": "ISO_3166-1" },
    "code_string": "GB"
  },
  "category": {
    "_type": "DV_CODED_TEXT",
    "value": "event",
    "defining_code": {
      "_type": "CODE_PHRASE",
      "terminology_id": { "_type": "TERMINOLOGY_ID", "value": "openehr" },
      "code_string": "433"
    }
  },
  "composer": { "_type": "PARTY_IDENTIFIED", "name": "Dr Alice Smith" },
  "content": [
    {
      "_type": "OBSERVATION",
      "name": { "_type": "DV_TEXT", "value": "Blood Pressure" },
      "archetype_node_id": "openEHR-EHR-OBSERVATION.blood_pressure.v2",
      "data": {
        "_type": "HISTORY",
        "events": [
          {
            "_type": "POINT_EVENT",
            "time": { "_type": "DV_DATE_TIME", "value": "2025-05-25T09:15:00+01:00" },
            "data": {
              "_type": "ITEM_TREE",
              "items": [
                {
                  "_type": "ELEMENT",
                  "name": { "_type": "DV_TEXT", "value": "Systolic" },
                  "value": { "_type": "DV_QUANTITY", "magnitude": 120.0, "units": "mm[Hg]" }
                },
                {
                  "_type": "ELEMENT",
                  "name": { "_type": "DV_TEXT", "value": "Diastolic" },
                  "value": { "_type": "DV_QUANTITY", "magnitude": 80.0, "units": "mm[Hg]" }
                }
              ]
            }
          }
        ]
      }
    }
  ]
}

2 — Deserialise back

var restored = OpenEhrJsonSerializer.Deserialize<Composition>(json);

// Verify round-trip fidelity
Debug.Assert(restored!.Name.Value == composition.Name.Value);

// Access typed values — _type drives concrete type resolution
var obs = (Observation)restored.Content[0];
var tree = (ItemTree)obs.Data.Events[0].Data;
var systolic = (DvQuantity)((Element)tree.Items[0]).Value!;
Console.WriteLine($"Systolic: {systolic.Magnitude} {systolic.Units}"); // 120 mm[Hg]

3 — Save to and read from a file

// Write
await File.WriteAllTextAsync("vital-signs.json", json, Encoding.UTF8);

// Read back
string stored = await File.ReadAllTextAsync("vital-signs.json");
var fromFile  = OpenEhrJsonSerializer.Deserialize<Composition>(stored);

4 — Async stream round-trip (HTTP POST → GET)

using var client = new HttpClient { BaseAddress = new Uri("https://cdr.hospital.example/ehrbase/") };

// POST a new composition
var postContent = new StringContent(json, Encoding.UTF8, "application/json");
var postResponse = await client.PostAsync(
    $"rest/openehr/v1/ehr/{ehrId}/composition", postContent);
postResponse.EnsureSuccessStatusCode();

// GET it back and deserialise from the response stream
var getResponse = await client.GetAsync(
    $"rest/openehr/v1/ehr/{ehrId}/composition/{compositionVersionId}");
getResponse.EnsureSuccessStatusCode();

await using var body = await getResponse.Content.ReadAsStreamAsync();
var cdrComposition = await OpenEhrJsonSerializer.DeserializeAsync<Composition>(body);

5 — Wrapping in a Version<Composition>

When submitting to a CDR that expects versioned payloads:

string versionJson = OpenEhrJsonSerializer.Serialize(version, writeIndented: true);

// Deserialise a versioned response
var restoredVersion = OpenEhrJsonSerializer.Deserialize<OriginalVersion<Composition>>(versionJson);
var innerComposition = restoredVersion!.Data;

See also