Este es el segundo artículo de la serie de introducción a FHIR Terminology. Repasaremos los conceptos fundamentales que conforman el módulo de Terminology de FHIR. Veremos ejemplos concretos de los problemas que puede resolver y ofreceremos una visión general de cómo encajan las distintas piezas.
Casos de uso
Como mencionamos anteriormente, hemos observado que quienes se inician en FHIR suelen aprovechar poco las soluciones de Terminology. Creemos que parte del motivo es la falta de conocimiento sobre los problemas que puede resolver; algunas personas asocian Terminology con temas como estándares, conformidad, cumplimiento normativo o regulaciones. Por eso pensamos que un buen punto de partida es mostrar algunos casos de uso concretos que se implementan fácilmente mediante un servidor de terminología. De hecho, todos estos ejemplos se ejecutan en tiempo real contra nuestra instancia de sandbox.
Cada pestaña muestra un ejemplo en vivo, desde cuadros de búsqueda y listas desplegables hasta mapeo y traducción; abra el panel en la parte inferior del recuadro para ver las solicitudes y respuestas reales1.
Contexto
Cuando un médico escribe «ataque al corazón» y otro escribe «infarto de miocardio», se refieren a lo mismo. Pero para un sistema informático, o cualquier flujo de trabajo a escala, son simplemente dos cadenas de texto distintas. La capacidad de compartir significado entre las partes es fundamental para la interoperabilidad. Para eso existen las terminologías sanitarias. Uno de los primeros ejemplos de terminología sanitaria es la Clasificación Internacional de Enfermedades (CIE), adoptada en 1893 para codificar las causas de muerte. Es anterior al software y sigue en uso hoy en día.
Trabajaremos con un conjunto de construcciones que se enmarcan en la definición de una terminología: taxonomías, ontologías, nomenclaturas, conjuntos de códigos, vocabularios, clasificaciones. A efectos prácticos, las llamaremos terminologías y las definiremos como un conjunto de términos con un identificador estable legible por máquina. Pueden ser infinitas, tener sinónimos, propiedades, relaciones, estructura, etc. Pero la característica principal que necesitaremos es que cada elemento tenga un identificador estable (código) y alguna etiqueta textual (término/display).
En el desarrollo web «convencional», los implementadores utilizan terminologías constantemente (aunque no se llamen así). Con frecuencia se implementan como enumeraciones o como una tabla de elementos con una vista de administración CRUD (es muy habitual que las enumeraciones sean sus propios códigos y que las tablas de elementos usen el identificador de la base de datos como identificador). Los ejemplos anteriores podrían perfectamente haberse implementado con estos patrones.
FHIR proporciona un Módulo de Terminology diseñado para resolver estos y otros problemas. Un aspecto interesante es que las mismas abstracciones permiten expresar tanto grandes ontologías estándar, conformes y autorizadas, como listas locales cortas de códigos similares a enumeraciones.
Valores codificados
Muchos recursos FHIR tienen campos cuyo dominio de valores posibles se extrae de una lista (una terminología). Sus valores son códigos asignados externamente que identifican un concepto definido. Por ejemplo:
resourceType: Patient
name:
- given: [Jane]
family: Doe
gender: female
Observe que, en este caso, name es una propiedad sin restricciones: puede tomar cualquier nombre humano, mientras que gender solo puede tomar uno de cuatro valores: male, female, other, unknown. En este caso, female es un valor codificado.
Un valor codificado es principalmente un par compuesto por «system» y «code», donde system es una URL2 que identifica el sistema de códigos (terminología) que define los códigos. Esta decisión tiene implicaciones significativas en la capacidad de descubrimiento de los valores codificados: en lugar de encontrar una cadena de texto que casualmente parece un código LOINC, los valores codificados van acompañados de su identificador de sistema de códigos. En el caso del género anterior, el sistema es implícito (Administrative Gender, http://hl7.org/fhir/administrative-gender); veremos por qué en breve.
FHIR define 3 tipos de datos principales para representar estos códigos3: code, Coding y CodeableConcept.
code: La instancia representa únicamente el código. El sistema es implícito.Coding: El tipo de dato contiene un código y un sistema que identifica el origen de la definición del código.CodeableConcept: Un tipo que representa un concepto mediante texto libre y/o uno o más elementoscoding.
La mayoría de los elementos codificados en FHIR utilizan CodeableConcept, ya que ofrece la mayor flexibilidad. Permite múltiples codificaciones y texto libre para expresar, por ejemplo, lo que una persona introdujo manualmente o los casos en que no hay código disponible. También facilita la transición, ya que es posible incluir códigos antiguos y nuevos en la misma estructura (véase el ejemplo de Observation más adelante).
El tipo de dato Coding se utiliza cuando la intención es referenciar un código específico, no expresar un concepto de forma general. El uso de Coding es poco frecuente, ya que es menos flexible que CodeableConcept y no permite texto libre ni traducciones.
El tipo de dato code aparece habitualmente en escenarios similares a enumeraciones. Típicamente, estos elementos tienen una fuerza de vinculación required, es decir: el código debe provenir obligatoriamente del conjunto de valores especificado y no es necesario expresar un código alternativo. Por lo general, estos elementos pueden estar involucrados en la lógica de negocio, como la distribución según un valor, la comparación exacta, etc. Por ejemplo: el estado de un recurso; el código del cliente podría ignorar los recursos retired o actuar solo sobre los active.
Vinculación
En los tipos de datos anteriores, los códigos son de tipo string; la forma de restringir el conjunto de valores que pueden tomar es mediante vinculaciones. La especificación vincula el elemento a un conjunto de valores, lo que significa que solo puede tomar valores de esa lista.
Las vinculaciones tienen dos propiedades principales: valueSet y strength. valueSet define qué códigos son válidos para este elemento. strength indica cómo debe interpretarse la vinculación: required, extensible, preferred, example.

En el ejemplo anterior, Patient.gender está vinculado al conjunto de valores Administrative Gender con una fuerza required; por lo tanto, gender solo puede ser: male, female, other, unknown. Y maritalStatus está vinculado a Marital Status Codes con una fuerza extensible, lo que significa que los códigos deben provenir de ese conjunto de valores salvo que el código esperado no esté incluido.
Ejemplos de valores codificados
resourceType: Patient
name:
- given: [Jane]
family: Doe
gender: female # code / AdministrativeGender (implicit)
maritalStatus: # CodeableConcept
text: Married
coding:
- system: http://terminology.hl7.org/CodeSystem/v3-MaritalStatus
code: M
display: Married
resourceType: Location
name : South Wing Neuro OR 1
status: suspended # code / LocationStatus (implicit)
operationalStatus: # Coding
system: http://terminology.hl7.org/CodeSystem/v2-0116
code: H
display: Housekeeping
type: # CodeableConcept
coding:
- system: http://terminology.hl7.org/CodeSystem/v3-RoleCode
code: RNEU
display: Neuroradiology unit
form: # CodeableConcept without codings
text: Room
resourceType: Observation
status: final # code / ObservationStatus (implicit)
code: # CodeableConcept with local and standard codings
coding:
- system: http://acmelabs.org
code: 104177
display: "Blood culture"
- system: http://loinc.org
code: 600-7
display: Bacteria identified in Blood by Culture
valueCodeableConcept: # CodeableConcept
coding:
- system: http://snomed.info/sct
code: 3092008
display: Staphylococcus aureus
interpretation:
text: Positive
coding:
- system: http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation
code: POS
Recursos
A continuación, examinaremos brevemente los recursos FHIR involucrados en el módulo de Terminology. En la práctica, rara vez se crean directamente. Generalmente se mantienen en otro lugar y se cargan4 en un servidor de terminología (o desde él).
El módulo de Terminology define cuatro recursos de terminología principales: CodeSystem, ValueSet, ConceptMap y NamingSystem. Dedicaremos un artículo a cada uno de ellos. Por ahora, ofreceremos una breve visión general de CodeSystem y ValueSet.
CodeSystem
CodeSystem es posiblemente el recurso más importante en FHIR Terminology. Se utiliza para describir un sistema de códigos, sus atributos y su contenido. En su forma más habitual, contiene una lista de conceptos, cada uno con su código, designaciones y propiedades.
Ejemplos
resourceType: CodeSystem
url: http://hl7.org/fhir/administrative-gender
version: 5.0.0
content: complete
status: active
concept:
- code: male
display: Male
- code: female
display: Female
- code: other
display: Other
- code: unknown
display: Unknown
resourceType: CodeSystem
content: supplement
supplements: http://hl7.org/fhir/administrative-gender
concept:
- code: male
designation:
- language: es
value: Masculino
- code: female
designation:
- language: es
value: Femenino
- code: other
designation:
- language: es
value: Otro
- code: unknown
designation:
- language: es
value: Desconocido
resourceType: CodeSystem
url: http://www.nlm.nih.gov/research/umls/rxnorm
version: '03022026'
publisher: National Library of Medicine
content: complete
filter:
- code: concept
operator: [is-a, generalizes, descendent-of]
value: comma-separated list of concept codes for direct equality testing
- code: NDC
operator: [=,in, exists]
value: NDC code
property:
- {code: TTY, type: string}
- {code: NDC, type: string}
- {code: RXN_STRENGTH, type: string}
- {code: dose_form_of, type: code}
- {code: has_ingredient, type: code}
- {code: has_tradename, type: code}
# ...
concept:
- code: '5640'
display: ibuprofen
property:
- code: TTY
valueString: IN
- code: has_tradename
valueCode: '1100067'
- code: ingredient_of
valueCode: '1152223'
- code: part_of
valueCode: '821036'
# ...
# ...
resourceType: CodeSystem
url: http://hl7.org/fhir/sid/icd-10-cm
version: '2025'
content: complete
property:
- description: Indicator [...] transactions ("billable code")
type: integer
code: valid
filter:
- description: Identify valid billable codes.
value: 0 = "header" – not valid [...]
code: valid
operator: ["="]
valueSet: http://hl7.org/fhir/sid/icd-10-cm/vs
concept:
- code: Chapter-1
display: Certain infectious and parasitic diseases (A00-B99)
concept:
- code: Section-A00-A09
display: Intestinal infectious diseases (A00-A09)
concept:
- code: A00
display: Cholera
concept:
- code: A00.0
display: Cholera due to Vibrio cholerae 01, biovar cholerae
property:
- code: valid
valueInteger: 1
# ...
ValueSet
Un recurso ValueSet especifica un conjunto de códigos extraídos de uno o más sistemas de códigos.
En nuestra experiencia, este es uno de los recursos más incomprendidos en FHIR Terminology. Una posible razón es que la diferencia entre sistemas de códigos y conjuntos de valores no siempre resulta clara para los implementadores. No ayuda el hecho de que, en el núcleo de FHIR, la mayoría de los recursos CodeSystem tienen un ValueSet equivalente que incluye todos sus códigos. Por ejemplo: http://hl7.org/fhir/administrative-gender y http://hl7.org/fhir/ValueSet/administrative-gender.
La distinción principal es que los sistemas de códigos contienen la definición de los conceptos, su origen, mientras que los conjuntos de valores seleccionan códigos de los sistemas de códigos. Por lo tanto, un conjunto de valores puede contener un subconjunto de un sistema de códigos, o incluso combinar varios.
Por ejemplo, RxNorm es una terminología de medicamentos que incluye conceptos para nombres comerciales, principios activos, formas farmacéuticas, etc. Podemos definir un conjunto de valores de los principios activos en RxNorm. Los conceptos incluidos seguirían siendo conceptos de RxNorm, pero solo tendríamos principios activos.
Otro caso de uso habitual para los conjuntos de valores es añadir una opción nula. Supongamos que usamos ISO 3166 (códigos de país) en un formulario. Muestra correctamente todos los países y sus códigos, pero no existe un código de país «Desconocido». Podemos definir un conjunto de valores que incluya todos los códigos de ISO 3166 y el concepto UNK de NullFlavor.
Ejemplos
resourceType: ValueSet
url: http://example.org/rxnorm-ingredients
title: RxNorm Ingredients
compose:
include:
- system: http://www.nlm.nih.gov/research/umls/rxnorm
filter:
- property: TTY
op: =
value: IN
resourceType: ValueSet
url: http://hl7.org/fhir/ValueSet/example
title: LOINC Codes for Cholesterol in Serum/Plasma
compose:
include:
- system: http://loinc.org
concept:
- code: 14647-2
display: Cholesterol [Moles/Volume]
- code: 2093-3
display: Cholesterol [Mass/Volume]
- code: 35200-5
display: Cholesterol [Mass Or Moles/Volume]
- code: 9342-7
display: Cholesterol [Percentile]
resourceType: ValueSet
url: http://hl7.org/fhir/ValueSet/administrative-gender
status: active
compose:
include:
- system: http://hl7.org/fhir/administrative-gender
resourceType: ValueSet
url: http://hl7.org/fhir/ValueSet/yesnodontknow
name: YesNoDontKnow
compose:
include:
- valueSet: ["http://terminology.hl7.org/ValueSet/v2-0136"]
- system: http://terminology.hl7.org/CodeSystem/data-absent-reason
concept:
- code: asked-unknown
display: Don't know
Operaciones
La principal forma de interactuar con el módulo de Terminology y sus recursos es a través de operaciones. La especificación R6 define 8 operaciones específicas de terminología. A lo largo de esta serie, examinaremos la mayoría de ellas en detalle. En este artículo presentaremos $expand, la que impulsa la mayoría de los ejemplos anteriores.
ValueSet/$expand
Dado un conjunto de valores, devuelve la lista de códigos que define. Esta operación es ideal para rellenar elementos de interfaz de usuario: listas desplegables, campos de búsqueda, selectores de códigos, etc. Además del conjunto de valores, se puede especificar un filtro de búsqueda de texto, paginación, las propiedades y designaciones que se deben devolver, el idioma de respuesta, entre otros parámetros.
Tomemos nuestro primer ejemplo: un campo de búsqueda predictiva sobre los hallazgos clínicos de SNOMED. Supongamos que queremos buscar «diabetes mellitus» y obtener 10 resultados. A continuación se muestra cómo podría verse una solicitud:
GET https://tx-sandbox.health-samurai.io/fhir/ValueSet/$expand
[Query]
url: http://snomed.info/sct?fhir_vs=isa/404684003
count: 10
filter: diabetes mellitus
curl -G 'https://tx-sandbox.health-samurai.io/fhir/ValueSet/$expand' \
--data-urlencode 'url=http://snomed.info/sct?fhir_vs=isa/404684003' \
--data-urlencode 'count=10' \
--data-urlencode 'filter=diabetes mellitus'
| Parámetro | Valor | Explicación |
|---|---|---|
url | http://snomed.info/sct?fhir_vs=isa/404684003 | URL implícita para los conceptos de hallazgos clínicos de SNOMED5 |
count | 10 | Número de conceptos a encontrar |
filter | diabetes mellitus | Texto a buscar |
También podemos proporcionar un conjunto de valores directamente en la solicitud, lo que nos permite construir consultas sobre un sistema de códigos mediante propiedades. Por ejemplo, supongamos que queremos obtener todos los medicamentos de marca que tienen tanto cafeína como acetaminofén como principios activos.
POST https://tx-sandbox.health-samurai.io/fhir/ValueSet/$expand
Content-Type: application/json
{
"resourceType": "Parameters",
"parameter": [
{
"name": "valueSet",
"resource": {
"resourceType": "ValueSet",
"status": "active",
"compose": {
"include": [
{
"system": "http://www.nlm.nih.gov/research/umls/rxnorm",
"filter": [
{ "property": "TTY", "op": "=", "value": "BN" },
{ "property": "tradename_of", "op": "=", "value": "CUI:161" },
{ "property": "tradename_of", "op": "=", "value": "CUI:1886" }
]
}
]
}
}
}
]
}
curl -X POST 'https://tx-sandbox.health-samurai.io/fhir/ValueSet/$expand' \
-H 'Content-Type: application/json' \
-d '{
"resourceType": "Parameters",
"parameter": [
{
"name": "valueSet",
"resource": {
"resourceType": "ValueSet",
"status": "active",
"compose": {
"include": [
{
"system": "http://www.nlm.nih.gov/research/umls/rxnorm",
"filter": [
{ "property": "TTY", "op": "=", "value": "BN" },
{ "property": "tradename_of", "op": "=", "value": "CUI:161" },
{ "property": "tradename_of", "op": "=", "value": "CUI:1886" }
]
}
]
}
}
}
]
}'
| Filtro | Valor | Explicación |
|---|---|---|
TTY | BN | Solo nombres comerciales |
tradename_of | CUI:161 | Contiene acetaminofén |
tradename_of | CUI:1886 | Contiene cafeína |
A continuación
En nuestro próximo artículo examinaremos los canónicos. Cómo se identifican los recursos de terminología, qué convenciones se utilizan y cómo funciona el versionado y la resolución.
- Anterior: Introducción a FHIR Terminology
- Siguiente: Canónicos — próximamente
Footnotes
-
La forma más eficiente de implementar algunos de estos ejemplos es usando agrupación por lotes; mantenemos las solicitudes aisladas para facilitar su inspección. ↩
-
Profundizaremos en el funcionamiento de estas URL en un artículo futuro sobre canónicos. ↩
-
La especificación en realidad define 4 tipos de datos (y 3 adicionales). Sin embargo,
CodeableReferencese define en términos deCodeableConcepty los adicionales son casos especiales. Por eso nos centramos en los tres primeros. Véase https://build.fhir.org/terminologies.html. ↩ -
En un artículo futuro veremos un tutorial para configurar un servidor de terminología que impulse una aplicación sanitaria desde cero. ↩
-
Véase https://terminology.hl7.org/en/SNOMEDCT.html para saber cómo usar SNOMED con FHIR Terminology. Dedicaremos un artículo futuro a SNOMED CT. ↩





