Search code examples
jsonflutterdarthl7-fhir

Json oneOf in Dart/Flutter for FHIR resources


I'm trying to create Dart classes for FHIR resources defined in Json. The full Json schema for FHIR is here if anyone wants to look. My issue is with a oneOf declaration. Specifically, I have a class like the following (I'm not including the full class definition here, although I can if anyone thinks it would be helpful):

class Bundle_Entry {
  Resource resource;

Bundle_Entry(this.resource});

  factory Bundle_Entry.fromJson(Map<String, dynamic> json) => _$Bundle_EntryFromJson(json);
  Map<String, dynamic> toJson() => _$Bundle_EntryToJson(this);
} 

My problem is that ResourceList is defined as oneOf a number of other classes.

"ResourceList": {
  "oneOf": [
    { "$ref": "#/definitions/Account" },
    { "$ref": "#/definitions/ActivityDefinition" },
    ...
  ]
}

I've tried declaring the 'resource' variable as types 'var', 'dynamic', and 'ResourceList' and created a class ResourceList that just contains a resource.

Each resource has a field titled 'resourceType', so I've also tried creating a ResourceList function that returns different types based on argument of 'resourceType', which also doesn't work.

If I do an http request, the actual response I'm trying to parse looks like this:

{
  "resourceType": "Bundle",
  "type": "searchset",
  "entry": [
      {
          "resource": {
              "name": "Jaba the Hutt"
              "birthDate": "1980-07-27",
              "id": "b26646dd-c549-4981-834e-bb4145d104b8",
              "resourceType": "Patient"
           }
      }
    ]
}

Any suggestions would be appreciated.

Updating my question. It's interesting, that the first answer is similar to what I've come up with currently.

class Bundle_Entry {
  dynamic resource;
  Bundle_Entry({this.resource});

  Bundle_Entry.fromJson(Map<String, dynamic> json) =>
      Bundle_Entry(
        resource: json['resource'] == null
        ? null
        : ResourceTypes(
            json['resource']['resourceType'], json['resource'] as Map<String, dynamic>)
);}

  Map<String, dynamic> toJson() => _$Bundle_EntryToJson(this);
}

dynamic ResourceTypes(String type, Map<String, dynamic> json) {
  if (type == 'Element') return (new Element.fromJson(json));
  if (type == 'Extension') return (new Extension.fromJson(json));
  if (type == 'Patient') return (new Narrative.fromJson(json));

My issue is that then I have to hard code each ResourceType, and it seemed like there should be an easier way.


Solution

  • I have been trying to build a similar thing. I approached it using inheritance and created a function to return the resource based on the ResourceType field.

    Resource getResource(json) {
      if(json == null) return null;
      if(json["resourceType"] == "Patient") return Patient.fromJson(json);
      if(json["resourceType"]=="Procedure") return Procedure.fromJson(json);
      if(json["resourceType"]=="Encounter") return Encounter.fromJson(json);
      if(json["resourceType"]=="Appointment") return Appointment.fromJson(json);
      if(json["resourceType"]=="Slot") return Slot.fromJson(json);
      if(json["resourceType"]=="Slot") return Slot.fromJson(json);
      if(json["resourceType"]=="Observation") return Observation.fromJson(json);
      if(json["resourceType"]=="Condition") return Condition.fromJson(json);
      if(json["resourceType"]=="DiagnosticReport") return DiagnosticReport.fromJson(json);
      if(json["resourceType"]=="MedicationRequest") return MedicationRequest.fromJson(json);
      if(json["resourceType"]=="CarePlan") return CarePlan.fromJson(json);
      if(json["resourceType"]=="Practitioner") return Practitioner.fromJson(json);
      if(json["resourceType"]=="AllergyIntolerance") return AllergyIntolerance.fromJson(json);
    
      return Resource.fromJson(json);
    }
    

    Where Patient, Procedure, etc. are subclasses of Resource:

    class Entry {
      String fullUrl;
      Resource resource;
    
      factory Entry.fromJson(Map<String, dynamic> json) => Entry(
            fullUrl: json["fullUrl"] == null ? null : json["fullUrl"],
    
            //This line is the magic
            resource: getResource(json["resource"]),
            search: json["search"] == null ? null : Search.fromJson(json["search"]),
            response: json["response"] == null
                ? null
                : Response.fromJson(json["response"]),
          );