Decide whether a resource is safe to summarize
Before a resource is rolled into a summary, a card, or a feed, ask whether anything in it changes the
meaning of what you are about to show. readSafety answers that in one call, over the whole
document rather than its root alone:
import { parseResource, readSafety } from "@cosyte/fhir";
const { resource } = parseResource(
'{"resourceType":"Observation","status":"entered-in-error","code":{"text":"synthetic"}}',
);
const safety = readSafety(resource);
safety.status; // => "entered-in-error"
safety.retracted; // => true
safety.negations; // => ["entered-in-error"]
negations is the authoritative field. The single-valued conveniences beside it, such as status
and retracted, describe the resource you handed in, while negations covers every resource inside
it too, so a retracted entry in a Bundle is visible there and nowhere else.
Read modifier elements and intents
Some elements change the meaning of a record without being a status. A patient recorded as deceased,
a patient record replaced by another (link), and a subpotent immunization dose are each reported on
modifierElements with their location, whatever value they carry, and each makes the resource unsafe
to summarize. A medication request's intent is mandatory, so it is surfaced instead: intents
pairs the code with its location, and only an intent that is not one of the eight R4 codes refuses.
import { parseResource, readSafety } from "@cosyte/fhir";
const patient = readSafety(
parseResource('{"resourceType":"Patient","deceasedBoolean":true}').resource,
);
patient.modifierElements; // => [{ element: "deceased", location: "Patient.deceasedBoolean" }]
patient.safeToSummarize; // => false
const request = readSafety(
parseResource('{"resourceType":"MedicationRequest","status":"active","intent":"proposal"}')
.resource,
);
request.intents; // => [{ code: "proposal", location: "MedicationRequest.intent" }]
request.safeToSummarize; // => true
Read the use of identifiers, names and addresses
An identifier, a name, an address, or a contact point can be marked old or temp, and FHIR treats
that use as a modifier: an old address is not where the patient lives now. datatypeUses pairs each
use with its location, on every identifier of the resource types the safety readout models and
on a patient's name, telecom, and address, including those of each contact. A readable code
leaves the resource safe to summarize, old included, because which entry to show is your decision:
nothing is filtered, reordered, or marked current for you. A use that is not one of the codes FHIR
defines for that datatype, such as "OLD" or "maiden" on an identifier, is located on
unreadableDatatypeUses instead and the resource is not safe to summarize.
import { parseResource, readSafety } from "@cosyte/fhir";
const person = readSafety(
parseResource('{"resourceType":"Patient","address":[{"use":"old","city":"Nowhere"}]}').resource,
);
person.datatypeUses; // => [{ code: "old", location: "Patient.address[0].use" }]
person.safeToSummarize; // => true
const unreadable = readSafety(
parseResource('{"resourceType":"Patient","identifier":[{"use":"OLD","value":"SYN-0001"}]}').resource,
);
unreadable.unreadableDatatypeUses; // => ["Patient.identifier[0].use"]
unreadable.safeToSummarize; // => false
What this does not read: a practitioner's identifiers, names, and addresses (a practitioner's
identifier use is reported on modifierElements instead, whatever its value), a use carried in an
extension value, a contained resource of a type the safety readout does not model, such as an
organization, and an ended period on an entry whose use is current.
Refuse instead of warn
When a summary must refuse rather than warn, assertSafeToSummarize is the executable form of the
same rule: it throws a FhirSafetyError for an unhandled modifier, a value the document left
ambiguous, and the other shapes that make an affirmative summary unsafe. The error carries the
locations that forced the refusal and never a value:
import { assertSafeToSummarize, FhirSafetyError, parseResource } from "@cosyte/fhir";
const { resource } = parseResource(
'{"resourceType":"Observation","status":"final","modifierExtension":[{"url":"http://example.org/local-flag","valueBoolean":true}]}',
);
const refusedAt = (): readonly string[] => {
try {
assertSafeToSummarize(resource);
return [];
} catch (err) {
if (err instanceof FhirSafetyError) return err.locations;
throw err;
}
};
refusedAt(); // => ["Observation.modifierExtension[0]"]
Call it first in any helper that flattens a resource into a summary, so an unknown modifier stops the summary instead of disappearing from it.
Reference
readSafetyand the fields ofSafetyReadout.assertSafeToSummarizeandFhirSafetyError.- Troubleshooting
covers the unknown
modifierExtensioncase and what to do about it.