Schreiben

<< Klicken Sie, um das Inhaltsverzeichnis anzuzeigen >>

Navigation:  Schnittstellen > FHIR Server (+) >

Schreiben

Der FHIR Server nimmt eingehende Daten als Observation (Einzelwerte) und QuestionnaireResponse (Formulare) an. Drei Eigenschaften vorweg:

1.Patienten werden nicht angelegt. Stammdaten werden ausschließlich in EMIL gepflegt. POST /Patient und PUT /Patient/<id> antworten mit 405 Method Not Allowed. Ermitteln Sie zuerst per GET /Patient?identifier=... die interne ID.

2.Whitelist pro Client. Geschrieben werden dürfen nur ItemType-IDs, die in der Spalte Erlaubte ItemTypen (inbound) des Clients freigegeben sind (siehe Clients verwalten). Standard ist leer, also kein Schreibrecht.

3.Idempotent. Ein POST /Observation mit (Subject, Visit-Datum, ItemType), zu dem schon ein Item existiert, überschreibt das bestehende. Mehrfaches Senden desselben Bodys ist sicher.

Observation schreiben: Beispiel Körpergewicht

Sie wollen für einen Patienten an einem bestimmten Datum das Körpergewicht (ItemType 10038) eintragen.

Schritt A: ItemType nachschlagen

GET /fhir/CodeSystem/itemtype/?_count=2000

Im Ergebnis nach „Körpergewicht“ suchen (oder den ItemType im Datendictionary nachsehen):

{ "code": "10038",

"display": "Körpergewicht",

"property": [

{ "code": "area", "valueCode": "V" },

{ "code": "unit", "valueString": "kg" },

{ "code": "variable", "valueString": "GEWICHT" },

{ "code": "kind", "valueCode": "number" }

]

}

Das heißt: ItemType 10038, Bereich V (Verlauf), Einheit kg, Datentyp number. Der Wert muss also als valueQuantity mit Einheit kg kommen.

Schritt B: ItemType für den Client freischalten

Unter Administration|Schnittstellen|FHIR R4 Server beim betreffenden Client in der Spalte Erlaubte ItemTypen (inbound) klicken, im Auswahldialog „Körpergewicht“ ankreuzen, OK. Die Freigabe wirkt sofort (siehe Wann Änderungen wirken).

Schritt C: Patient-ID besorgen

GET /fhir/Patient?identifier=K12345

Authorization: Bearer <token>

→ aus der Antwort die id entnehmen, z. B. 42.

Schritt D: Observation senden

POST /fhir/Observation

Authorization: Bearer <token>

Content-Type: application/fhir+json

{

"resourceType": "Observation",

"status": "final",

"subject": { "reference": "Patient/42" },

"code": {

"coding": [{

"system": "https://emil.itc-ms.de/fhir/sid/itemtype",

"code": "10038"

}]

},

"effectiveDateTime": "2026-05-17",

"valueQuantity": {

"value": 72.5,

"unit": "kg",

"system": "http://unitsofmeasure.org"

}

}

Antwort: 201 Created, Header Location: .../Observation/<itemid> und Body:

{

"resourceType": "OperationOutcome",

"issue": [{

"severity": "information",

"code": "informational",

"diagnostics": "Observation gespeichert: Patient/42, Encounter/142862, Observation/2247369."

}]

}

Die Item-ID (hier 2247369) können Sie für spätere Updates per PUT merken. Den Encounter (142862) hat der Server am Datum gefunden oder neu angelegt. Der Wert erscheint sofort im Client; der Audit-Trail verzeichnet den Client als Urheber.

Weitere Fälle beim Schreiben von Observations

Visit-Auflösung

Ist keine encounter.reference angegeben, sucht der Server eine vorhandene Visit am effectiveDateTime-Datum für das Subject, im passenden Bereich (V für normale Visits, L für Labor, F für Stammdaten). Existiert keine, legt er sie an. Mehrere Observations zum selben Datum landen damit in derselben Visit.

Alternativ können Sie eine bestehende Visit gezielt referenzieren, wenn Sie deren ID kennen (z. B. aus einem vorherigen Bundle-Export); sie muss zum Patienten gehören:

"encounter": { "reference": "Encounter/142862" }

Auswahlwerte (SLIST/MLIST)

Für ItemTypes mit kind=slist oder kind=mlist verwendet der Body valueCodeableConcept mit einem oder mehreren coding[]-Einträgen. Die Codes haben die Form <typeid>/<rawcode> wie im CodeSystem dokumentiert; das $-Präfix aus der Datenbank wird nicht mitgeschickt.

Beispiel für eine Mehrfachauswahl „Allergien“ (fiktiver ItemType 12345 aus dem CodeSystem-Beispiel) mit zwei gewählten Codes:

POST /fhir/Observation

Authorization: Bearer <token>

Content-Type: application/fhir+json

{

"resourceType": "Observation",

"status": "final",

"subject": { "reference": "Patient/42" },

"code": {

"coding": [{

"system": "https://emil.itc-ms.de/fhir/sid/itemtype",

"code": "12345"

}]

},

"effectiveDateTime": "2026-05-17",

"valueCodeableConcept": {

"coding": [

{ "system": "https://emil.itc-ms.de/fhir/sid/itemtype", "code": "12345/POLLEN" },

{ "system": "https://emil.itc-ms.de/fhir/sid/itemtype", "code": "12345/PEANUT" }

]

}

}

Für kind=slist (Einfachauswahl): genau ein coding[]-Eintrag.

Freitext

Textfelder (kind=text…) erhalten den Wert als valueString, hier „Sonstige Befunde“ (ItemType 10080):

POST /fhir/Observation

Authorization: Bearer <token>

Content-Type: application/fhir+json

{

"resourceType": "Observation",

"status": "final",

"subject": { "reference": "Patient/42" },

"code": { "coding": [{ "system": "https://emil.itc-ms.de/fhir/sid/itemtype", "code": "10080" }] },

"effectiveDateTime": "2026-05-17",

"valueString": "Patient klagt über Müdigkeit nach Belastung."

}

Update (PUT)

Den Wert eines bereits geschriebenen Items ändern:

PUT /fhir/Observation/2247369

Authorization: Bearer <token>

Content-Type: application/fhir+json

{ ... gleicher Body wie oben, mit geändertem value ... }

→ 200 OK. Bei nicht existierender ID: 404 Not Found (kein Update-as-Create).

POST oder PUT? Für normale Schreibvorgänge reicht POST, er ist idempotent (gleicher Body, gleicher Endzustand). PUT brauchen Sie nur, wenn Sie ausdrücklich ein bestimmtes Item per ID ansprechen wollen.

QuestionnaireResponse schreiben

Für Form-ItemTypes (kind form/calcform/custform/custhform) wird jedes Formularfeld ein item[]-Eintrag mit linkId und answer[0].value[x]. Vorgehen wie bei der Observation:

1.ItemType-ID nachschlagen (CodeSystem/itemtype, kind-Property prüfen).

2.Den ItemType in der Spalte Erlaubte ItemTypen (inbound) des Clients freischalten.

3.Patient-ID besorgen.

4.POST schicken.

Einfaches Formular (z. B. HAQ, ItemType 50123)

Die linkId sind die Feldnamen des Formulars; beim HAQ sind es die Auswahlfelder rbN (angekreuzte Felder speichert der Server als "1", siehe Checkboxen unten).

POST /fhir/QuestionnaireResponse

Authorization: Bearer <token>

Content-Type: application/fhir+json

{

"resourceType": "QuestionnaireResponse",

"status": "completed",

"questionnaire": "Questionnaire/50123",

"subject": { "reference": "Patient/42" },

"authored": "2026-05-17",

"item": [

{ "linkId": "rb2", "answer": [{ "valueBoolean": true }] },

{ "linkId": "rb10", "answer": [{ "valueBoolean": true }] },

{ "linkId": "rb19", "answer": [{ "valueBoolean": true }] }

]

}

Bei kind=calcform (wie dem HAQ) berechnet der Server den Score (im Speicherformat vor #255) selbst; ein mitgesendetes linkId="score" wird bei der nächsten Neuberechnung überschrieben.

Formular mit mehreren Einträgen (Multiform)

Für Form-Items, in denen mehrere strukturierte Einträge untereinander stehen (z. B. eine Medikamentenliste): oberste item[]-Einträge mit linkId="row" und verschachteltem item[] je Zeile. Beispiel „RheCORD Medikation“ (ItemType 52086, Felder name und instructions):

POST /fhir/QuestionnaireResponse

Authorization: Bearer <token>

Content-Type: application/fhir+json

{

"resourceType": "QuestionnaireResponse",

"status": "completed",

"questionnaire": "Questionnaire/52086",

"subject": { "reference": "Patient/42" },

"authored": "2026-05-17",

"item": [

{ "linkId": "row", "item": [

{ "linkId": "name", "answer": [{ "valueString": "Methotrexat" }] },

{ "linkId": "instructions", "answer": [{ "valueString": "15 mg 1x wöchentlich s.c." }] }

]},

{ "linkId": "row", "item": [

{ "linkId": "name", "answer": [{ "valueString": "Folsäure" }] },

{ "linkId": "instructions", "answer": [{ "valueString": "5 mg 1x wöchentlich" }] }

]}

]

}

Checkboxen

Checkboxen stehen im Speicherformat nur, wenn sie angekreuzt sind. Beim Schreiben:

{ "linkId": "cbprednisolon", "answer": [{ "valueBoolean": true }] }

→ landet als "cbprednisolon": "1" im Storage. false oder Weglassen führt dazu, dass der Eintrag nicht erzeugt wird.

Rücklieferung per transaction-Bundle

Fest verdrahtete Schnittstellen (RheCORD) liefern Ergebnisse per POST /fhir mit Bundle.type=transaction (alternativ POST /fhir/$transaction). Das Bundle enthält eine minimale Patient-Ressource (Identifier im aktiven System laut $pid-config, dazu Nach- und Vorname zum Abgleich) und eine oder mehrere QuestionnaireResponse und/oder Observation, deren subject.reference per urn:uuid auf den Patient-Eintrag zeigt.

•Patienten werden nur aufgelöst, nicht angelegt. Der Namensabgleich (Vollname) unterscheidet nicht zwischen Groß- und Kleinschreibung; das Geburtsdatum wird nicht geprüft.

•Ist der Identifier nicht auflösbar oder weicht der Name ab, wird das gesamte Bundle mit einem OperationOutcome abgelehnt; es entsteht keine verwaiste QuestionnaireResponse.

•Antwort: Bundle.type=transaction-response mit response.status je Eintrag. Bundle.type=batch wird nicht verarbeitet.