|
7 min de lectura
|

SDK de Python para FHIR: desarrolle aplicaciones con Type Schema

Resumir este artículo con:
ChatGPTPerplexityClaudeGrok

Type Schema: SDK de Python para FHIR

Actualización: Este artículo describe el MVP original basado en fhir-schema-codegen. El SDK de Python se ha trasladado a @atomic-ehr/codegen con mejoras significativas: tree shaking, bundles polimórficos, extensiones primitivas, integración con fhirpy y más. Consulte la publicación actualizada: @atomic-ehr/codegen: Python FHIR Types.

Recientemente anunciamos Type Schema—una nueva forma independiente del lenguaje para construir SDKs a partir de paquetes FHIR. Hoy veremos nuestro MVP del SDK de Python y mostraremos cómo agiliza el desarrollo con FHIR desde la primera instalación hasta una excelente experiencia de desarrollo. Al generar automáticamente modelos con tipado fuerte y útiles funciones auxiliares de cliente, el SDK elimina horas de código repetitivo y de manipulación manual de esquemas. En resumen: los equipos pueden pasar de un concepto a un prototipo conforme a FHIR en una sola tarde, sin necesidad de profundizar en la especificación FHIR.

En esta publicación usted:

  • Aprenderá a generar un SDK de Python para cualquier paquete FHIR
  • Verá el SDK en acción, con comprobación de tipos y gestión de errores
  • Descubrirá opciones para personalizar el SDK en sus propios proyectos

Descripción general del SDK de Python para FHIR

Nuestro SDK de Python tiene dos partes principales:

  • Operaciones: métodos para las funciones de creación, lectura, actualización, eliminación y búsqueda
  • Recursos y tipos de datos: clases como Patient, Encounter y Marital Status Code.

Para este MVP, nos centramos principalmente en las definiciones de recursos, manteniendo un soporte básico para las operaciones.

Construido sobre Pydantic, el SDK ofrece una buena validación y conversión de JSON a Python, y funciona bien con Python.

Genere el SDK para su paquete FHIR

  • Instale nuestro generador:
$ npm install -g @fhirschema/codegen
  • Ejecute el generador del SDK de Python:
$ npx fscg generate -g python -p hl7.fhir.r4.core@4.0.1 -o my-python-project --py-sdk-package aidbox

donde:

  • -p hl7.fhir.r4.core@4.0.1—el paquete FHIR que se utilizará
  • -o my-python-project—dónde colocar su proyecto Python
  • --py-sdk-package aidbox—el nombre de su paquete SDK (todo el código generado irá en my-python-project/aidbox).

Eso es todo: ahora dispone de un SDK de Python listo para usar con FHIR R4.

¿No tiene servidor FHIR? Ponga uno en marcha en 2 minutos

Siga estos pasos:

  1. Inicie el servidor FHIR Aidbox:
$ curl -JO https://aidbox.app/runme/sdk && docker compose up --wait
  1. Obtenga una licencia de Aidbox (solo la primera vez):
  • Abra http://localhost:8080
  • Siga las instrucciones de configuración en su navegador
  • Obtenga el secreto de cliente de la variable de entorno BOX_ROOT_CLIENT_SECRET del archivo docker-compose.yml y utilícelo en la inicialización del cliente.

Conéctese al servidor FHIR

Antes de empezar a trabajar con el SDK, instale las dependencias de Python necesarias. Puede hacerlo ejecutando:

$ cd my-python-project
$ pip install -r my-python-project/aidbox/requirements.txt

Para trabajar con un servidor FHIR mediante nuestro SDK, necesita configurar un cliente:

from aidbox.client import Client, Auth, AuthCredentials

client = Client(
    base_url="http://localhost:8080/fhir",
    auth=Auth(
        method="basic",
        credentials=AuthCredentials(
            username="root",
            password="secret", # don't forget to update
        ),
    ),
)

Después podrá usar los métodos del cliente para operaciones CRUD: client.create, client.read, client.update, client.delete y client.search.

Cree y procese recursos FHIR

Vamos a crear un recurso Patient:

  • Importe las clases que necesita y cree un Patient:
from aidbox.hl7_fhir_r4_core import Patient, HumanName, Identifier
patient = Patient(
    identifier=[Identifier(system="http://org.io/id", value="0000-0000")],
    name=[HumanName(given=["John"], family="Doe")],
    gender="male",
)
  • Guárdelo en el servidor y vea los resultados:
result = client.create(patient)
print(result.to_json(indent=2))
from pprint import pprint
pprint(result.model_dump(exclude_unset=True, exclude_none=True))
{
  "resourceType": "Patient",
  "id": "859316db-8428-40ae-9a63-c2cbe088f540",
  "meta": {
    "extension": [
      {
        "url": "https://aidbox.app/ex/createdAt",
        "valueInstant": "2025-06-06T11:07:47.062435Z"
      }
    ],
    "lastUpdated": "2025-06-06T11:07:47.062435Z",
    "versionId": "195"
  },
  "gender": "male",
  "identifier": [
    {
      "system": "http://org.io/id",
      "value": "0000-0000"
    }
  ],
  "name": [
    {
      "family": "Doe",
      "given": [
        "John"
      ]
    }
  ]
}
{'gender': 'male',
 'id': '859316db-8428-40ae-9a63-c2cbe088f540',
 'identifier': [{'system': 'http://org.io/id', 'value': '0000-0000'}],
 'meta': {'extension': [{'url': 'https://aidbox.app/ex/createdAt',
                         'valueInstant': '2025-06-06T11:07:47.062435Z'}],
          'lastUpdated': '2025-06-06T11:07:47.062435Z',
          'versionId': '195'},
 'name': [{'family': 'Doe', 'given': ['John']}],
 'resourceType': 'Patient'}

El ejemplo completo está disponible aquí: example/python/main.py.

Gestión de errores con comprobación de tipos y validación en tiempo de ejecución

¿Qué ocurre si cometemos un error? Intentemos añadir un campo y un valor incorrectos:

Patient(
    name=[HumanName(family="Doe")],
    gender="FOO",            # wrong value
    some_data="1990-01-01",  # wrong field
)

Primero, comprobemos los tipos. Podemos usar mypy para ello, pero necesitamos habilitar el plugin pydantic.mypy en mypy.ini:

[mypy]
plugins = pydantic.mypy

Ahora podemos ejecutar mypy para comprobar nuestro código:

$ mypy . --strict
main.py:59: error: Unexpected keyword argument "some_data" for "Patient"  [call-arg]
Found 1 error in 1 file (checked 155 source files)

Obtenemos un error de tipo estático: ¡nada mal para Python!

Ahora veamos qué ocurre cuando lo ejecutamos:

$ python main.py
Traceback (most recent call last):
  File "/fhir-schema-codegen/example/python/main.py", line 59, in <module>
    Patient(
    ~~~~~~~^
        name=[HumanName(family="Doe")],
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        gender="FOO",  # wrong value
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        some_data="1990-01-01",  # wrong field
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/fhir-schema-codegen/example/python/venv/lib/python3.13/site-packages/pydantic/main.py", line 253, in __init__
    validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
pydantic_core._pydantic_core.ValidationError: 2 validation errors for Patient
gender
  Input should be 'male', 'female', 'other' or 'unknown' [type=literal_error, input_value='FOO', input_type=str]
    For further information visit https://errors.pydantic.dev/2.11/v/literal_error
some_data
  Extra inputs are not permitted [type=extra_forbidden, input_value='1990-01-01', input_type=str]
    For further information visit https://errors.pydantic.dev/2.11/v/extra_forbidden

Ahora vemos ambos errores con mensajes informativos:

  • El código exacto que generó el error
  • El error del campo gender: lo que proporcionamos ('FOO') y lo que debería ser
  • El error del campo some_data: no se permiten campos adicionales

¡Bastante útil!

Personalización del SDK

A continuación se presentan algunas formas de personalizar el SDK de Python:

Trabajo con recursos no estándar

Suponga que sus datos incluyen atributos adicionales, como un Patient con un lotteryNumber:

>>> patient_json = """
... {
...   "resourceType": "Patient",
...   "name": [ { "family": "Doe", "given": [ "John" ] } ],
...   "lotteryNumber": 123456
... }
... """
... patient = Patient.from_json(patient_json)
...
pydantic_core._pydantic_core.ValidationError: 1 validation error for Patient
lotteryNumber
  Extra inputs are not permitted [type=extra_forbidden, input_value=123456, input_type=int]
    For further information visit https://errors.pydantic.dev/2.11/v/extra_forbidden

Por defecto, el SDK rechaza esto. Para solucionarlo, añada el indicador --py-allow-extra-fields al generar:

$ npx fscg generate -g python -p hl7.fhir.r4.core@4.0.1 -o my-python-project --py-sdk-package aidbox --py-allow-extra-fields

Ahora puede:

  • Analizar JSON que contenga campos adicionales
  • Enviarlo al servidor FHIR sin los campos adicionales
  • Acceder a los campos adicionales en su código
>>> p = Patient.from_json(patient_json)
>>> p.to_json()
{'resourceType': 'Patient', 'name': [{'family': 'Doe', 'given': ['John']}]}
>>> p.model_extra
{'lotteryNumber': 123456}

Nota: Esto ilustra por qué la generación de código es mejor que un SDK universal. Con la generación, podemos crear código sencillo y de propósito específico que resulta fácil de leer. Un SDK universal requeriría un código mucho más complejo.

Añada soporte para recursos personalizados

Crear recursos FHIR personalizados debería ser igual de sencillo que usar los estándar. Simplemente añada su recurso personalizado al proceso de generación.

Veamos un ejemplo de recurso personalizado de Health Samurai: Aidbox Notify via Custom Resources.

En este proyecto de demostración, definimos recursos personalizados mediante FHIR Schema: TutorNotificationTemplate y TutorNotification. Podemos guardarlos como archivos JSON y pasarlos al generador del SDK:

npx fscg generate -g python -p hl7.fhir.r4.core@4.0.1 \
    --fhir-schema example/custom_resources/TutorNotification.fs.json \
    --fhir-schema example/custom_resources/TutorNotificationTemplate.fs.json \
    --py-sdk-package aidbox -o $(PYTHON_SDK_EXAMPLE)

Y en la salida encontraremos el código generado para estos recursos, como:

class TutorNotificationTemplate(DomainResource):
    model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid")

    resource_type: str = Field(
        default='TutorNotificationTemplate',
        alias='resourceType',
        serialization_alias='resourceType',
        frozen=True,
        pattern='TutorNotificationTemplate'
    )

    template: str | None = Field(None, alias="template", serialization_alias="template")

    def to_json(self, indent: int | None = None) -> str:
        return self.model_dump_json(exclude_unset=True, exclude_none=True, indent=indent)

    @classmethod
    def from_json(cls, json: str) -> TutorNotificationTemplate:
        return cls.model_validate_json(json)

Esto le permite adaptar el SDK a sus necesidades específicas.

Nota: Otra ventaja de la generación de código es la facilidad de actualización. Si necesita migrar a una nueva versión de FHIR, simplemente regenere el SDK. Su IDE resaltará todos los lugares donde necesita actualizar el código. Esto es mucho más sencillo que intentar adaptar un SDK universal.

Personalización del SDK

¿Necesita cambiar el funcionamiento del SDK? Nuestros generadores son de código abierto, por lo que puede personalizarlos. Por ejemplo, si solo necesita procesar datos FHIR y no requiere conexión a un servidor, puede eliminar el código del cliente.

Hay tres formas de hacerlo:

  • Manual: Simplemente elimine los archivos que no necesite después de la generación

  • Modificar el generador: Haga un fork de fhir-schema-codegen

  • Abra src/generators/python/index.ts

  • Localice el método generate

  • Elimine la línea con this.copyStaticFiles()

  • Ahora dispone de un generador que solo crea definiciones de tipos

  • Contribuir. Añada un indicador de línea de comandos como --py-only-type al generador y envíe un PR.

¿Listo para desarrollar?

Hemos mostrado cómo generar y utilizar nuestro SDK de Python para FHIR. El código funciona con comprobación estática de tipos y le ofrece un excelente soporte de IDE.

Explore el ejemplo del SDK de Python y consulte test_sdk.py para conocer métodos adicionales del cliente.

Código fuente del generador: GitHub – fhir‑schema‑codegen Especificación de Type Schema: GitHub – type‑schema

Conéctese conmigo—Aleksandr Penskoi—en LinkedIn para hablar sobre sus necesidades específicas, o únase a nosotros en el canal de Zulip de Type Schema.

Véase también: Implementación de FHIR en lenguajes dinámicos.

Compartir este artículo
Comments
Comments
Sign in
Loading comments...
Subscribe to our blog

Get the latest articles on FHIR, interoperability, and healthcare IT.