FHIR se ha convertido en el estándar principal para el intercambio de datos de salud. Para comenzar con FHIR, los desarrolladores necesitan leer la especificación de FHIR y las guías de implementación (IGs, como US Core, MCODE, etc.), e implementarlas en su lenguaje de programación. Los SDK de FHIR simplifican este proceso al ofrecer herramientas bien documentadas que funcionan de forma natural dentro del lenguaje de programación del desarrollador.
En esta entrada, explicaremos qué es un SDK de FHIR, por qué crear un SDK propio puede ser mejor que utilizar uno universal, y cómo Type Schema, una herramienta de código abierto, le ayuda a generar un SDK personalizado adaptado a sus recursos FHIR específicos.
¿Qué Contiene un SDK de FHIR?
Para construir un SDK de FHIR útil, es importante comprender sus responsabilidades principales: cómo se comunica con el servidor FHIR y cómo gestiona los datos estructurados. Veamos qué incluye un SDK típico:
- Operaciones, como CRUD, búsqueda y otras formas de interactuar con los datos.
- Recursos y tipos de datos, como Patient, Encounter, Marital Status Code, etc.
En el lado de las operaciones, el SDK proporciona métodos para comunicarse con un servidor FHIR. Incluye funciones para construir URLs, serializar datos, gestionar la paginación, autenticación, inicio de sesión y más. Por ejemplo:
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);
Nota de implementación: Estas partes trabajan estrechamente con las herramientas del lenguaje de programación, como las bibliotecas HTTP y la gestión de tareas asíncronas. Idealmente, el SDK debe ser nativo para el stack de su proyecto.
En el lado de los recursos, un SDK proporciona tipos o clases que coinciden con las definiciones de recursos FHIR, incluyendo sus campos y restricciones (más de 150 en la especificación básica de FHIR). Deben ser nativos en su lenguaje:
const patient = new Patient({
name: [
new HumanName({
family: "Smith",
given: ["John"]
})
],
birthDate: "1970-01-01"
});
Nota de implementación: Dado el número de recursos, el código se genera habitualmente de forma automática. Los tipos de recursos también pueden integrarse con la parte de operaciones del SDK (p. ej., patrón active record).
¿Por qué Generar un SDK en lugar de Usar uno Universal?
Un SDK de FHIR universal (que funcione con todas las características y versiones de FHIR) presenta varios desafíos:
- No es viable combinar todos los perfiles porque cada IG tiene requisitos estructurales y de validación únicos.
- Los recursos y operaciones personalizados a menudo no están cubiertos por el FHIR estándar.
- Los proyectos del mundo real tienen stacks tecnológicos específicos. Añadir un framework de gran tamaño puede generar conflictos.
- Incluir todas las características de FHIR haría el SDK demasiado complejo para la mayoría de los proyectos reales.
Al mismo tiempo, construir un SDK de FHIR desde cero es difícil para alguien nuevo en FHIR (como intentar construir un ORM después de aprender SQL por primera vez). Los mayores desafíos son:
- Mapear estructuras de datos complejas y perfiles a un lenguaje de programación, incluyendo características inusuales como Choice Types o Extensions
- Gestionar paquetes FHIR y resolver conflictos de versiones
- Representar ValueSets (es decir, listas de valores permitidos)
La mayoría de los desafíos pertenecen a la capa de recursos/tipos del SDK. Para simplificar el desarrollo de SDK de FHIR, hemos creado Type Schema.

¿Qué es FHIR Type Schema?
Type Schema es una herramienta impulsada por la comunidad que facilita el desarrollo de SDK de FHIR.
La especificación FHIR Schema es un formato JSON que representa los datos de FHIR de una manera fácil de aprender y a partir de la cual generar código. He aquí por qué:
- Unificación. Type Schema representa todos los elementos FHIR (Resources, Types, ValueSets, etc.) de forma consistente y fácil de convertir en código.
- Aplanamiento. Type Schema le proporciona acceso directo a los campos y sus tipos, evitando rutas complejas. Todos los esquemas pueden almacenarse de forma sencilla en un diccionario para la generación de código en un solo paso.
- Enriquecimiento. Incluye información adicional necesaria para la generación de código, como los valores posibles de los ValueSets y todos los tipos dependientes.
FHIR Schema Tools son utilidades de código abierto (con licencia MIT) que crean Type Schemas para FHIR, IGs y sus recursos personalizados.
La herramienta principal es Type Schema, que toma paquetes y definiciones de recursos personalizados y genera Type Schemas listos para la generación de código.
También puede leer más aquí:
¿Cómo Generar Tipos con Type Schema?
Veamos un ejemplo. Comenzaremos con el recurso Patient de hl7.fhir.r4.core en TypeScript y mostraremos cómo generar este código a partir de Type Schema paso a paso.
Los ejemplos de código completos están disponibles aquí:
- Entrada: Patient.ts.json (generado por fhir-clj/type-schema)
- Salida: Patient.ts (generado por fhir-schema/fhir-schema-codegen)
- Tipos TypeScript para Type Schema: typeschema.ts
Importar Dependencias de Tipos
Dado que hl7.fhir.r4.core incluye muchos recursos y tipos, colocarlos en un solo archivo no es práctico. En su lugar, los importamos:
import { Address } from './Address';
import { Attachment } from './Attachment';
// ...
Puede generar las importaciones con:
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');
Todos los archivos pueden generarse de la misma manera que para el recurso Patient.
Definición de Tipos Anidados
Los recursos FHIR tienen estructuras anidadas complejas. Dado que muchos lenguajes no admiten definiciones de tipos anidados, generamos tipos locales:
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[];
}
Puede generar esto a partir del campo .nested, con todas las dependencias ya importadas:
for (const subtype of schema.nested) {
this.generateType(subtype);
}
donde generateType es una función que recibe un esquema de tipo y produce una definición de tipo. Los detalles se encuentran en la siguiente sección.
Generación de Tipos
¿Qué tenemos en este paso?
- Todos los tipos externos importados
- Todos los archivos anidados definidos
Veamos algunos casos (omitiendo extensiones y la mayoría de los campos):
export interface Patient extends DomainResource {
active?: boolean;
link?: PatientLink[];
gender?: 'male' | 'female' | 'other' | 'unknown';
multipleBirthBoolean?: boolean;
multipleBirthInteger?: number;
// ...
}
La primera línea de la definición de tipo es sencilla: tomamos el nombre del tipo de .identifier.name y el tipo base de .base.name.
export interface Patient extends DomainResource {
{
"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" }
}
Los campos se generan analizando .fields y se mapean según el tipo:
- Los tipos primitivos se mapean directamente a tipos nativos en el lenguaje destino. Por ejemplo:
const typeMap = { boolean: 'boolean'... } - Los tipos complejos/anidados usan sus nombres definidos porque ya los importamos o definimos.
- Los arrays llevan el sufijo
[]al final del nombre.
active?: boolean;
link?: PatientLink[];
{
"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
}
}
Para los campos con vinculación a ValueSet (listas de valores permitidos), Type Schema proporciona los valores posibles para que podamos añadirlos directamente a nuestro tipo:
gender?: 'male' | 'female' | 'other' | 'unknown';
{
"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" ]
}
}
Para los choice types (campos que pueden adoptar diferentes tipos), este ejemplo utiliza un enfoque sencillo creando campos separados sin validación adicional. Para otras opciones, véase: Choice Type Representation.
multipleBirthBoolean?: boolean;
multipleBirthInteger?: number;
{
"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
}
}
Esto es solo un vistazo a la generación de código de SDK de FHIR con Type Schema, pero como puede ver, es sencillo si sabe qué resultado desea obtener.
Pruébelo Usted Mismo
Para generar tipos de SDK:
- Instale el generador de código:
npm install -g @fhirschema/codegen
- Genere tipos para
• TypeScript:
npx @fhirschema/codegen generate -g typescript -p 'hl7.fhir.r4.core@4.0.1' -o out
• Python:
npx @fhirschema/codegen generate -g python -p 'hl7.fhir.r4.core@4.0.1' -o out
• C#:
npx @fhirschema/codegen generate -g csharp -p 'hl7.fhir.r4.core@4.0.1' -o out
Para más detalles, consulte: fhir-schema-codegen.
Conclusión
En esta entrada, hemos presentado Type Schema como una herramienta para simplificar el desarrollo de SDK de FHIR. Al proporcionar un formato estandarizado para las entidades de datos de FHIR, los desarrolladores pueden generar SDK personalizados adaptados a sus necesidades sin partir de cero.
Planes Futuros
Type Schema todavía está en desarrollo temprano. Las mejoras próximas incluyen:
- Mejor soporte para Profiles, ValueSets, Extensions, Operations, etc.
- Un «Libro de recetas del SDK de FHIR» con ejemplos que muestran cómo mapear FHIR a diferentes lenguajes de programación.
- Herramientas mejoradas para gestionar múltiples paquetes y resolver conflictos.
Únase a Nuestra Comunidad
Ayúdenos a mejorar Type Schema:
- Inicie una discusión o reporte problemas: GitHub Issues
- Añada sus propios ejemplos, funcionalidades o correcciones: GitHub Repo
- Hable con nosotros: Zulip
Véase también: Type Schema: SDK de Python para FHIR e Implementación de FHIR en lenguajes dinámicos.




