About the medical history

data4life implementations can feature a questionnaire about a user’s medical history, also called anamnesis or health history (German: medizinische Vorgeschichte, Anamnese). The questionnaire contains questions about the medial history of a person. The information is usually entered at the beginning of the user journey. For example, the medical history contains information about the following for a person:

  • Personal data

  • Conditions and diagnoses

  • Risk factors

  • Allergies

  • Emergency contacts

FHIR implementation

The Fast Healthcare Interoperability Resources (FHIR) standard is missing a special medical history resource. Instead, information is stored in different FHIR resources, depending on the type of information, and marked with a medical history identifier where needed:

  • Patient resource for information contained in the Patient resource, such as name and biological sex.

  • Questionnaire and QuestionnaireResponse resources for custom questions that can’t be mapped to an existing FHIR resource or where additional specifications would be required for FHIR compliance. See 'when to use questionnaires'.

  • Observation resource for specific data points that can be mapped to Observations, such as a patient’s body height and weight. Not in use at the moment.

Application integrators can display an overview of a patient’s medical history or display data like a doctor’s form. With the help of the SDK, you can customize the aggregation and display of these resources as a coherent medical history section.

The SDK passes through any valid FHIR resource sent to the SDK, not restricted to the ones mentioned above. The current approach is to use minimal number of attributes that the respective FHIR resource or an application design requires. You can provide additional information as long as it is valid FHIR. But it will not be displayed in data4life apps and might be lost when the provided resources are updated through an application other than your client.

Example: Patient resource

Currently it is assumed that the first stored Patient resource contains the relevant data. Other instances are not considered for fetching and writing medical history data.

Fetching information

A good place to start is by fetching the stored patient information.

 const patientResource = await HealthCloud.fetchResources(userId, {
    resourceType: 'Patient'
  });

  // In the future, patient management resource will be managed more strictly by the app.
  if (patientResource && patientResource.records && patientResource.records.length) {
    const patient = patientResource.records[0];

    // All actual data is stored in the fhirResource
    const patientResource = patient['fhirResource'];
  }

Updating an existing Patient resource

A questionnaire in your app might ask users to update information. The updateResource method lets you send the update to the SDK.

A questionnaire in your application might ask the patient to update information, which you can send to the SDK as shown below.

const userId = GC.SDK.getCurrentUserId();

 // This could mean retrieving the information from your store
 const thePatient = {
     ...getCurrentPatientResource() // When updating information, avoid using a reference to your stored version
 };

thePatient.birthDate = document.getElementById('birthDate').value;

GC.SDK.updateResource(userId, thePatient); // Returns a promise with the new record which you could use to update your store

Creating a new Patient resource

Below is a sample implementation for how an application creates a new patient resource by using the createRecource method.

Patient resources created by clients other than data4life are not processed by data4life apps.
const userId = GC.SDK.getCurrentUserId();

const thePatient = { // The basic set of information for every patient
    resourceType: 'Patient',
    active: true,
    deceasedBoolean: false
  };

thePatient.gender = document.getElementById('gender').value;
thePatient.birthDate = document.getElementById('birthDate').value;
thePatient.name = [{
    use: 'usual',
    'given': [document.getElementById('givenName').value], // Array format
    'family': document.getElementById('familyName').value,
}];

GC.SDK.createResource(userId, thePatient); // Note: returns a promise with the created record which you could store

Example: Questionnaire and QuestionnaireResponse resources

Currently it is assumed that the first stored Questionnaire resource with a title and the first stored QuestionnaireResponse with an identifier of 'Anamnesis Questionnaire - custom questions' is the correct one.

The Questionnaire resource only contains the questions, whereas all answers are stored in the QuestionnaireResponse resource. Questions and their answers are linked through their linkId property.

Fetching information

const userId = GC.SDK.getCurrentUserId();
let questionId; // In this example, we find the first question and its answer

const questionnaireResource = await GC.SDK.fetchResources(userId, {
    resourceType: 'Questionnaire'
});

if (questionnaireResource && questionnaireResource.records && questionnaireResource.records.length) {
    const questionnaireRecords = questionnaireResource.records.map(
        record => record['fhirResource']
      );

    // Find a questionnaire with the medical history title
    const anamnesisQuestionnaire =
        questionnaireRecords.find(questionnaire => questionnaire.title === 'Anamnesis')

    // Example for finding a question
    if (anamnesisQuestionnaire) {
        questionId = anamnesisQuestionnaire.item[0].linkId;
    }

}

const questionnaireResponseResource = await GC.SDK.fetchResources(userId, {
    resourceType: 'QuestionnaireResponse'
});

if (questionnaireResponseResource && questionnaireResponseResource.records && questionnaireResponseResource.records.length) {
    const questionnaireResponseRecords = questionnaireResponseResource.records.map(
            record => record['fhirResource']
          );

    // Find a questionnaireResponse whose reference is the questionnaire's id
    const anamnesisQuestionnaireResponse =
        questionnaireResponseRecords.find(response => response.reference === anamnesisQuestionnaire.id)

    // Iterate through the `item` to find answers
    if (anamnesisQuestionnaireResponse) {
        const storedResponse = anamnesisQuestionnaireResponse.item.find(item => item.linkId === questionId);
    }
}

Updating information

Updates to the Questionnaire resource are only required when a question is added that has previously been unanswered. To add a question item:

function addQuestionToQuestionnaire(question) {
    const userId = GC.SDK.getCurrentUserId();

     // This could mean retrieving it from your store
    const theQuestionnaire = {
        ...getCurrentQuestionnaire() // Use object spread or other means to prevent mutation of stored questionnaire
    };

    const questionItem = {
        linkId: question.identifier,
        identifier: question.identifier,
      };

    theQuestionnaire.fhirResource.item = [...theQuestionnaire.fhirResource.item, questionItem];

    return GC.SDK.updateResource(userId, theQuestionnaire.fhirResource); // A promise that returns the new value
}

New or changed answers require an update to the QuestionnaireResponse object. To implement the object update:

function addQuestionAnswerToQuestionnaireResponse(response) {
    const userId = GC.SDK.getCurrentUserId();

     // This could mean retrieving it from your store
    const theQuestionnaireResponse = {
        ...getCurrentQuestionnaireResponse() // Use object spread or other means to prevent mutation of stored questionnaireResponse
    };

    const answerItem = {
        linkId: response.identifier,
        identifier: response.identifier,
        valueBoolean: [response.value], // FHIR QuestionnaireResponse requires an array
      };

    // A response might be a change of an already-existing answer
    const answerInExistingItemsIndex = theQuestionnaireResponse.fhirResource.item.findIndex(
          existingAnswer => existingAnswer.linkId === answerItem.linkId
    );

    // Add new responses to item prop, update existing responses
    if (answerInExistingItemsIndex !== -1) {
        questionnaireResponse.fhirResource.item[answerInExistingItems] = answerItem;
    } else {
        questionnaireResponse.fhirResource.item.push(answerItem);
    }

    // A promise that returns the updated resource
    return GC.SDK.updateResource(userId, questionnaireResponse.fhirResource);
}

Creating resources

The SDK allows the creation of Questionnaire and QuestionnaireResponse objects. The objects must be valid FHIR resources.

IMPORTANT: To ensure compatibility, third-party providers should contact data4life before creating their own medical history questionnaires.

To create the resources:

function createQuestionnaireAndAddQuestion(question) {
    const userId = GC.SDK.getCurrentUserId();

    const questionItem = {
        linkId: question.identifier,
        type: question.type,
        identifier: question.identifier,
        readOnly: false,
        repeats: false
    };

    const newQuestionnaire = {
        resourceType: 'Questionnaire',
        title: 'Anamnesis',
        status: 'active',
        subjectType: ['Patient'],
        item: [questionItem]
    };

    return GC.SDK.updateResource(userId, newQuestionnaire); // A promise that returns the new value
}
function createQuestionnaireResponseAndAddResponse(response) {
    const userId = GC.SDK.getCurrentUserId();

    const answerItem = {
        linkId: response.identifier,
        type: response.type,
        identifier: response.identifier,
        valueBoolean: [response.value], // Questionnaire response requires an array
    };

    const questionnaireRecord = getCurrentQuestionnaireRecord(); // Retrieve from your store

    const newQuestionnaireResponse = {
        resourceType: 'QuestionnaireResponse',
        identifier: 'Anamnesis',
        status: 'in-progress',
        item: [answerItem],
        questionnaire: {
            reference: questionnaireRecord.id,
        },
    };

    return GC.SDK.updateResource(userId, newQuestionnaireResponse); // A promise that returns the new value
}

Other resources

Support for other resources is currently not implemented.