nazrulworld / fhir.resources

FHIR Resources https://www.hl7.org/fhir/resourcelist.html
https://pypi.org/project/fhir.resources/
Other
393 stars 109 forks source link

Extend fhir.resources for a particular implementation guide #109

Open yvesonline opened 2 years ago

yvesonline commented 2 years ago

Description

We need to work with some FHIR data according to MIO DiGA V1.0.0 and I was wondering how to extend fhir.resources to make it possible to do so. For example the Patient resource of MIO DiGA is extended by a couple of attributes, so I was wondering where to start to get to a from mio.diga.patient import Patient. I'd inherit from fhir.resources.patient.Patient and then add the new attributes. I assume this is the way to go? Is there any documentation available regarding implementing custom FHIR resources?

What I Did

So far nothing.

bwalsh commented 1 year ago

@yvesonline Hello. I was wondering if you resolved this and what approach you took?

yvesonline commented 1 year ago

Yes @bwalsh we resolved this by directly using the Patient object, there wasn't a lot of added value in creating a dedicated MIO DiGA Patient class.

So we do something like this:

from datetime import datetime, timezone
from fhir.resources.patient import Patient

data = {
    'id': '...',
    'name': [
        {
            'text': '...',
            'use': 'official',
            'family': '...',
            'family__ext': {
                'extension': [
                    {
                        'url': 'http://hl7.org/fhir/StructureDefinition/humanname-own-name',
                        'valueString': '...',
                    },
                ],
            },
            'given': ['...'],
        },
    ],
    'identifier': [...],
    'meta': {
        'versionId': 1,
        'lastUpdated': datetime.now(tz=timezone.utc),
        'profile': [
            'https://fhir.kbv.de/StructureDefinition/KBV_PR_MIO_DIGA_Patient|1.0.0'
        ],
    },
    'telecom': [...],
    'communication': [...],
}

p = Patient(**data)
bobvanderlinden commented 12 months ago

I needed to define resources as part of Aidbox that weren't defined fhir.resources. It took some time to figure out, but eventually I came up with the following function:

def define_fhir_resource(
    fhirtypes,
    fhirtypesvalidators,
    cls: typing.Type[DomainResource],
) -> typing.Type[DomainResource]:
    resource_name = cls.__name__
    resource_type_name = f"{resource_name}Type"
    resource_validator_name = f"{resource_name.lower()}_validator"

    resource_type = type(
        resource_type_name,
        (fhirtypes.AbstractType,),
        {"__resource_type__": resource_name},
    )

    setattr(fhirtypes, resource_type_name, resource_type)
    fhirtypesvalidators.MODEL_CLASSES[resource_name] = (cls, None)

    def resource_validator(value):
        return fhirtypesvalidators.fhir_model_validator(resource_name, value)

    setattr(fhirtypesvalidators, resource_validator_name, resource_validator)

To use this to create a User resource:

from fhir.resources.R4B import fhirtypes
from fhir.resources.R4B import fhirtypesvalidators
from fhir.resources.R4B.domainresource import DomainResource
from pydantic import Field

class User(DomainResource):
    resource_type = Field("User", const=True)
    userName: str = Field(None, element_property=True)
    password: str = Field(None, element_property=True)

    @classmethod
    def elements_sequence(cls):
        return [
            "id",
            "meta",
            "implicitRules",
            "language",
            "text",
            "contained",
            "extension",
            "modifierExtension",
            "userName",
            "password",
        ]

define_fhir_resource(
    fhirtypes=fhirtypes, fhirtypesvalidators=fhirtypesvalidators, cls=User
)

This was needed because fhir.resources would try to look up UserType in its fhirtypes and user_validator in fhirtypesvalidators. The above isn't pretty, but I couldn't find a better solution.