---
{
  "title": "Type Schema: Ein pragmatischer Ansatz zur Erstellung eines FHIR SDK",
  "description": "FHIR hat sich zum primären Standard für den Austausch von Gesundheitsdaten entwickelt. Um mit FHIR zu beginnen, müssen Entwickler die FHIR-Spezifikation und Implementierungsleitfäden (IGs, wie US Core, MCODE usw.) lesen und diese dann in ihrer Programmiersprache umsetzen. FHIR SDKs vereinfachen diesen Prozess durch",
  "date": "2025-05-06",
  "author": "Aleksandr Penskoi, Gennady Razmakhnin",
  "reading-time": "10 min",
  "tags": [
    "FHIR Tools",
    "FHIR Standard",
    "Code Generation"
  ]
}
---
FHIR hat sich zum primären Standard für den Austausch von Gesundheitsdaten entwickelt. Um mit FHIR zu beginnen, müssen Entwickler die FHIR-Spezifikation und Implementierungsleitfäden (IGs, wie US Core, MCODE usw.) lesen und diese dann in ihrer Programmiersprache umsetzen. FHIR SDKs vereinfachen diesen Prozess, indem sie gut dokumentierte Werkzeuge bieten, die sich natürlich in die Programmiersprache eines Entwicklers einfügen.

In diesem Beitrag erläutern wir, was ein FHIR SDK ist, warum die Erstellung eines eigenen SDK besser sein kann als die Verwendung eines universellen, und wie Type Schema, ein Open-Source-Werkzeug, Ihnen hilft, ein maßgeschneidertes SDK für Ihre spezifischen FHIR-Ressourcen zu generieren.

## Was steckt in einem FHIR SDK?

Um ein nützliches FHIR SDK zu entwickeln, ist es wichtig, seine Kernaufgaben zu verstehen – wie es mit dem [FHIR-Server](https://www.health-samurai.io/fhir-server) kommuniziert und wie es strukturierte Daten verarbeitet. Schauen wir uns an, was ein typisches SDK umfasst:
- **Operationen** wie CRUD, Suche und andere Möglichkeiten zur Interaktion mit Daten.
- **Ressourcen** und Datentypen, wie Patient, Encounter, Marital Status Code usw.

**Auf der Operationsseite** stellt das SDK Methoden zur Kommunikation mit einem [FHIR-Server](https://www.health-samurai.io/fhir-server) bereit. Es enthält Funktionen zum Erstellen von URLs, zum Marshaling von Daten, zur Behandlung von Paginierung, zur Anmeldung, zur Authentifizierung und mehr. Zum Beispiel:


```javascript
const patient = await fhirClient.read('Patient', '123');

const observations = await fhirClient.search('Observation', {
  patient: 'Patient/123',
  code: 'http://loinc.org|8867-4',
  date: 'gt2022-01-01'
});

const result = await fhirClient.create(newPatientResource);
```


*Implementierungshinweis*: Diese Teile arbeiten eng mit den Werkzeugen Ihrer Programmiersprache zusammen, wie HTTP-Bibliotheken und der Art, wie asynchrone Aufgaben behandelt werden. Idealerweise sollte das SDK nativ zu Ihrem Projekt-Stack passen.

**Auf der Ressourcenseite** bietet ein SDK Typen oder Klassen, die FHIR-Ressourcendefinitionen einschließlich ihrer Felder und Einschränkungen entsprechen (über 150 in der grundlegenden FHIR-Spezifikation). Sie sollten in Ihrer Sprache natürlich verwendbar sein:


```javascript
const patient = new Patient({
  name: [
    new HumanName({
      family: "Smith",
      given: ["John"]
    })
  ],
  birthDate: "1970-01-01"
});
```


*Implementierungshinweis*: Angesichts der Anzahl der Ressourcen wird Code in der Regel automatisch generiert. Ressourcentypen können auch mit dem Operationsteil des SDK integriert werden (z. B. Active-Record-Muster).

## Warum ein SDK generieren statt ein universelles zu verwenden?

Ein universelles FHIR SDK (eines, das mit allen FHIR-Funktionen und -Versionen funktioniert) bringt mehrere Herausforderungen mit sich:
- Es ist nicht praktikabel, alle Profile zu kombinieren, da jedes IG einzigartige strukturelle und Validierungsanforderungen hat.
- Benutzerdefinierte Ressourcen und Operationen werden häufig nicht durch Standard-FHIR abgedeckt.
- Reale Projekte haben spezifische Technologie-Stacks. Das Hinzufügen eines umfangreichen Frameworks kann Konflikte verursachen.
- Die Aufnahme aller FHIR-Funktionen würde das SDK für die meisten realen Projekte zu komplex machen.

Gleichzeitig ist die Entwicklung eines FHIR SDK von Grund auf schwierig für jemanden, der neu bei FHIR ist (ähnlich wie der Versuch, ein ORM zu erstellen, nachdem man gerade SQL gelernt hat). Die größten Herausforderungen sind:
- Das Abbilden komplexer Datenstrukturen und Profile auf eine Programmiersprache, einschließlich ungewöhnlicher Funktionen wie Choice Types oder Extensions
- Das Verwalten von FHIR-Paketen und das Auflösen von Versionskonflikten
- Das Darstellen von ValueSets (d. h. Listen zulässiger Werte)

Die meisten Herausforderungen gehören zur Ressourcen-/Typen-Schicht des SDK. Um die FHIR SDK-Entwicklung zu vereinfachen, haben wir **Type Schema** entwickelt.
![FHIR SDK](image-1.avif)

## Was ist FHIR Type Schema?

Type Schema ist ein community-getriebenes Werkzeug, das die FHIR SDK-Entwicklung erleichtert.

Die **FHIR-Schema-Spezifikation** ist ein JSON-Format, das FHIR-Daten auf eine Weise darstellt, die leicht erlernbar und für die Code-Generierung geeignet ist. Hier ist der Grund:
- *Vereinheitlichung*. Type Schema stellt alle FHIR-Elemente (Ressourcen, Typen, ValueSets usw.) auf konsistente Weise dar, die leicht in Code umgewandelt werden kann.
- *Abflachung*. Type Schema ermöglicht direkten Zugriff auf Felder und deren Typen und vermeidet komplexe Pfade. Alle Schemas können einfach in einem Dictionary für die einpfadige Code-Generierung gespeichert werden.
- *Anreicherung*. Es enthält zusätzliche Informationen, die für die Code-Generierung benötigt werden, wie mögliche Werte aus ValueSets und alle abhängigen Typen.

**FHIR-Schema-Werkzeuge** sind Open-Source-Dienstprogramme (MIT-lizenziert), die Type Schemas für FHIR, IGs und Ihre benutzerdefinierten Ressourcen erstellen.

Das Hauptwerkzeug ist [Type Schema](https://github.com/fhir-clj/type-schema), das Pakete und benutzerdefinierte Ressourcendefinitionen entgegennimmt und Type Schemas erstellt, die für die Code-Generierung bereit sind.

Weitere Informationen finden Sie hier:
- [JSON Schema](https://github.com/fhir-clj/type-schema/blob/main/docs/type-schema.schema.json)
- [Beispiele für Type Schemas](https://github.com/fhir-clj/type-schema/tree/main/docs/examples)
- [Beispiel-SDK-Generatoren für TypeScript, Python, C#](https://github.com/fhir-schema/fhir-schema-codegen)

## Wie generiert man Typen mit Type Schema?

Betrachten wir ein Beispiel. Wir beginnen mit der Patient-Ressource aus `hl7.fhir.r4.core` in TypeScript und zeigen Schritt für Schritt, wie dieser Code aus Type Schema generiert wird.

Vollständige Code-Beispiele sind hier verfügbar:
- Eingabe: [Patient.ts.json](https://gist.github.com/ryukzak/18b40b542f2714fbd36e3cd5e72c612c) (erstellt von [fhir-clj/type-schema](https://github.com/fhir-clj/type-schema))
- Ausgabe: [Patient.ts](https://gist.github.com/ryukzak/b6004a18700ebcee35a79a7817d17c55) (erstellt von [fhir-schema/fhir-schema-codegen](https://github.com/fhir-schema/fhir-schema-codegen))
- TypeScript-Typen für Type Schema: [typeschema.ts](https://github.com/fhir-schema/fhir-schema-codegen/blob/main/src/typeschema.ts)

### Typabhängigkeiten importieren

Da `hl7.fhir.r4.core` viele Ressourcen und Typen enthält, ist es nicht praktikabel, sie in einer Datei zu platzieren. Stattdessen importieren wir sie:


```javascript
import { Address } from './Address';
import { Attachment } from './Attachment';
// ...
```


Sie können Importe wie folgt generieren:


```javascript
const deps = schema.dependencies
    // other types will be inlined or defined in this file
    .filter((dep) => ['complex-type', 'resource'].includes(dep.kind))
    .sort((a, b) => a.name.localeCompare(b.name))
    .map((dep) => `import { ${this.uppercaseFirstLetter(dep.name)} } from './${dep.name}'`)
    .join('\n');
```


Alle Dateien können auf dieselbe Weise wie für die Patient-Ressource generiert werden.

### Definition verschachtelter Typen

FHIR-Ressourcen haben komplexe verschachtelte Strukturen. Da viele Sprachen keine verschachtelten Typdefinitionen unterstützen, generieren wir lokale Typen:


```javascript
export interface PatientLink extends BackboneElement {
    other?: Reference<'Patient' | 'RelatedPerson'>;
    type?: 'replaced-by' | 'replaces' | 'refer' | 'seealso';
}

export interface PatientCommunication extends BackboneElement {
    language?: CodeableConcept;
    preferred?: boolean;
}

export interface PatientContact extends BackboneElement {
    address?: Address;
    gender?: 'male' | 'female' | 'other' | 'unknown';
    name?: HumanName;
    organization?: Reference<'Organization'>;
    period?: Period;
    relationship?: CodeableConcept[];
    telecom?: ContactPoint[];
}
```


Sie können dies aus dem `.nested`-Feld generieren, wobei alle Abhängigkeiten bereits importiert sind:


```javascript
for (const subtype of schema.nested) {
    this.generateType(subtype);
}
```


wobei `generateType` eine Funktion ist, die ein Typschema empfängt und eine Typdefinition erstellt. Details finden Sie im nächsten Abschnitt.

### Typgenerierung

Was haben wir an diesem Punkt?
- Alle externen Typen importiert
- Alle verschachtelten Dateien definiert

Betrachten wir einige Fälle (Extensions und die meisten Felder werden übersprungen):


```javascript
export interface Patient extends DomainResource {
    active?: boolean;
    link?: PatientLink[];
    gender?: 'male' | 'female' | 'other' | 'unknown';
    multipleBirthBoolean?: boolean;
    multipleBirthInteger?: number;
    // ...
}
```


Die erste Zeile der Typdefinition ist einfach: Wir nehmen den Typnamen aus `.identifier.name` und den Basistyp aus `.base.name`.


```javascript
export interface Patient extends DomainResource {
```



```javascript
{
  "identifier": { "kind": "resource", "package": "hl7.fhir.r4.core", "version": "4.0.1",
                 "name": "Patient", "url": "http://hl7.org/fhir/StructureDefinition/Patient" },
  "base": { "kind": "resource", "package": "hl7.fhir.r4.core", "version": "4.0.1",
            "name": "DomainResource", "url": "http://hl7.org/fhir/StructureDefinition/DomainResource" }
}
```


Felder werden durch Analyse von `.fields` generiert und basierend auf dem Typ zugeordnet:
- Primitive Typen werden direkt auf native Typen in der Zielsprache abgebildet. Zum Beispiel: `const typeMap = { boolean: 'boolean'... }`
- Komplexe/verschachtelte Typen verwenden ihre definierten Namen, da wir sie bereits importieren oder definieren.
- Arrays werden mit `[]` am Ende des Namens versehen.


```javascript
active?: boolean;
    link?: PatientLink[];
```



```javascript
{
  "active": {
      "type": { "kind": "primitive-type", "package": "hl7.fhir.r4.core", "version": "4.0.1",
                "name": "boolean", "url": "http://hl7.org/fhir/StructureDefinition/boolean" },
      "array": false,
      "required": false, "excluded": false
    },
  "link": {
    "type": { "kind": "nested", "package": "hl7.fhir.r4.core", "version": "4.0.1",
              "name": "link", "url": "http://hl7.org/fhir/StructureDefinition/Patient#link" },
    "array": true,
    "required": false, "excluded": false
  }
}
```


Für Felder mit **ValueSet-Bindung** (Listen zulässiger Werte) stellt Type Schema mögliche Werte bereit, sodass wir sie direkt in unserem Typ verwenden können:


```javascript
gender?: 'male' | 'female' | 'other' | 'unknown';
```



```javascript
{
  "gender": {
    "type": { "kind": "primitive-type", "package": "hl7.fhir.r4.core", "version": "4.0.1",
              "name": "code", "url": "http://hl7.org/fhir/StructureDefinition/code" },
    "array": false,
    "required": false, "excluded": false,
    "enum": [ "male", "female", "other", "unknown" ]
  }
}
```


Für Choice Types (Felder, die verschiedene Typen annehmen können) verwendet dieses Beispiel einen einfachen Ansatz, indem separate Felder ohne zusätzliche Validierung erstellt werden. Weitere Optionen finden Sie unter: [Choice Type Representation](https://github.com/fhir-clj/type-schema/blob/main/docs/choice-type.md).


```javascript
multipleBirthBoolean?: boolean;
    multipleBirthInteger?: number;
```



```javascript
{
  "multipleBirth": {
    "choices": [ "multipleBirthBoolean", "multipleBirthInteger" ],
    "array": false,
    "required": false, "excluded": false
  },
  "multipleBirthBoolean": {
    "choiceOf": "multipleBirth",
    "type": { "kind": "primitive-type", "package": "hl7.fhir.r4.core", "version": "4.0.1",
              "name": "boolean", "url": "http://hl7.org/fhir/StructureDefinition/boolean" },
    "array": false,
    "required": false, "excluded": false
  },
  "multipleBirthInteger": {
    "choiceOf": "multipleBirth",
    "type": { "kind": "primitive-type", "package": "hl7.fhir.r4.core", "version": "4.0.1",
              "name": "integer", "url": "http://hl7.org/fhir/StructureDefinition/integer" },
    "array": false,
    "required": false, "excluded": false
  }
}
```


Dies ist nur ein kurzer Einblick in die Generierung von FHIR SDK-Code mit Type Schema, aber wie Sie sehen können, ist es unkompliziert, wenn Sie wissen, was Sie erzeugen möchten.

### Probieren Sie es selbst aus

So generieren Sie SDK-Typen:

1. Code-Generator installieren:


```javascript
npm install -g @fhirschema/codegen
```


2. Typen generieren für

**•** TypeScript:


```javascript
npx @fhirschema/codegen generate -g typescript -p 'hl7.fhir.r4.core@4.0.1' -o out
```


**•** Python:


```javascript
npx @fhirschema/codegen generate -g python -p 'hl7.fhir.r4.core@4.0.1' -o out
```


**•** C#:


```javascript
npx @fhirschema/codegen generate -g csharp -p 'hl7.fhir.r4.core@4.0.1' -o out
```


Weitere Details finden Sie unter: [fhir-schema-codegen](https://github.com/fhir-schema/fhir-schema-codegen).

## Fazit

In diesem Beitrag haben wir Type Schema als Werkzeug vorgestellt, das die FHIR SDK-Entwicklung vereinfacht. Durch die Bereitstellung eines standardisierten Formats für FHIR-Datenentitäten können Entwickler maßgeschneiderte SDKs generieren, die auf ihre Bedürfnisse zugeschnitten sind, ohne von Grund auf neu beginnen zu müssen.

### Zukunftspläne

Type Schema befindet sich noch in der frühen Entwicklung. Geplante Verbesserungen umfassen:
- Bessere Unterstützung für Profile, ValueSets, Extensions, Operationen usw.
- Ein „FHIR SDK Cookbook" mit Beispielen, die zeigen, wie FHIR auf verschiedene Programmiersprachen abgebildet werden kann.
- Verbesserte Werkzeuge für den Umgang mit mehreren Paketen und die Auflösung von Konflikten.

### Treten Sie unserer Community bei

Helfen Sie uns, Type Schema zu verbessern:
- Starten Sie eine Diskussion oder melden Sie Probleme: [GitHub Issues](https://github.com/fhir-clj/type-schema/issues)
- Fügen Sie eigene Beispiele, Funktionen oder Korrekturen hinzu: [GitHub Repo](https://github.com/fhir-clj/type-schema)
- Chatten Sie mit uns: [Zulip](https://chat.fhir.org/#narrow/channel/498057-Type-Schema)

Siehe auch: [Type Schema: Python SDK für FHIR](/blog/type-schema-python-sdk-for-fhir) und [FHIR in dynamischen Sprachen implementieren](/blog/implementing-fhir-in-dynamic-languages).