## On this page

Now that we have gone through all CRUD operations, we can put them together to effectively work with FHIR data. This guide will go through a common healthcare workflow, creating an order for lab tests (a.k.a. [`ServiceRequest`](/content/docs/api/fhir/resources/servicerequest/index.html) in FHIR) for patients and when the lab test is complete, creating results (a.k.a. [`Observation`](/content/docs/api/fhir/resources/observation/index.html) and [`DiagnosticReport`](/content/docs/api/fhir/resources/diagnosticreport/index.html) in FHIR) that correspond to the original [`ServiceRequest`](/content/docs/api/fhir/resources/servicerequest/index.html).

This example will illustrate how to create FHIR objects, how to update them, how to link them, and then how to read them back in bulk. Here is a breakdown of the workflow at a high level:

- Use FHIR batch request to create a [`Patient`](/content/docs/api/fhir/resources/patient/index.html) and a [`ServiceRequest`](/content/docs/api/fhir/resources/servicerequest/index.html).
  - This will use a conditional to only create the [`Patient`](/content/docs/api/fhir/resources/patient/index.html) if it does not already exist.
  - It will also link the [`ServiceRequest`](/content/docs/api/fhir/resources/servicerequest/index.html) to the [`Patient`](/content/docs/api/fhir/resources/patient/index.html).
- Create an [`Observation`](/content/docs/api/fhir/resources/observation/index.html) and [`DiagnosticReport`](/content/docs/api/fhir/resources/diagnosticreport/index.html).
- Read back the [`DiagnosticReport`](/content/docs/api/fhir/resources/diagnosticreport/index.html) and [`Observation`](/content/docs/api/fhir/resources/observation/index.html).
  - Use a batch request to read all [`Observation`](/content/docs/api/fhir/resources/observation/index.html) resources in one go, versus making multiple requests.

## Creating the Patient and Service Request

Creating a [`Patient`](/content/docs/api/fhir/resources/patient/index.html) and a [`ServiceRequest`](/content/docs/api/fhir/resources/servicerequest/index.html) sounds simple, but there are several nuances. If the [`Patient`](/content/docs/api/fhir/resources/patient/index.html) already exists, a new one should not be created. We also need to ensure that the [`ServiceRequest`](/content/docs/api/fhir/resources/servicerequest/index.html) is linked to the correct patient.

### Creating Patient

Creating a [`Patient`](/content/docs/api/fhir/resources/patient/index.html) if one does not exist uses the **conditional create** logic in FHIR. In this example, a patient has a Medical Record Number or MRN. If that MRN exists, then a new patient should not be created. In a lab workflow, it is common for a lab to serve patients repeatedly. In this case where there is already a patient in the system, it would be incorrect (and confusing) to make a new patient record.

```ts
import type { Patient } from '@medplum/fhirtypes';

import { randomUUID } from 'crypto';

// Generate an example MRN (Medical Record Number)
// We will use this in the "conditional create" and "upsert"
const exampleMrn = randomUUID();

const patientData: Patient = {
  resourceType: 'Patient',
  name: [{ given: ['Batch'], family: 'Test' }],
  birthDate: '2020-01-01',
  gender: 'female',
  identifier: [
    {
      system: 'https://namespace.example.health/',
      value: exampleMrn,
    },
  ],
};

// When creating an order, and if you don't know if the patient exists,
// you can use this MRN to check. Use the 'identifier=' search criterion for a
// conditional create: if a resource with the given `identifier` already exists,
// that resource will be returned instead.
const patient = await medplum.createResourceIfNoneExist(patientData, 'identifier=' + exampleMrn);
console.log('Patient record created', patient);
```

This example uses the [`MedplumClient`](/content/docs/sdk/core.medplumclient) from the Medplum SDK to interact with the FHIR API. The `createResourceIfNoneExists` method is a helper that performs a search before creating the resource.

The behavior of the `Patient.identifier` field is important to note. `Patient.identifier` usually has a reference string or URL that describes which system that identifier came from. [`Identifiers`](/content/docs/fhir-basics#naming-data-identifiers/index.html) are a concept in FHIR which describe the context in which that identifier is generated, for example, and identifier could be a Social Security Number (SSN) or be created by a health system for their own internal purposes. Here is an example of an identifier scheme for the [Australian Healthcare system](https://namespaces.digitalhealth.gov.au/id/hi/ihi/1.0/).

We recommend that providers put documentation of their identifier system online for interoperability purposes.

#### Performing an Upsert

In some cases, you may want to update the resource in place if it already exists in the system, in addition to creating it if it doesn't exist yet. This is accomplished via a combined "update" and "insert" operation: an "upsert".

Provide the current version of the resource and a search query, similar to `createResourceIfNoneExists()`.

```ts
// An "upsert" (i.e. update/insert) will either update the resource in place if it
// already exists, otherwise is will be created.  This is performed in a single,
// transactional request to guarantee data consistency.
const updatedPatient = medplum.upsertResource(patient, 'identifier=' + exampleMrn);
console.log('Patient record updated', updatedPatient);
```

```ts
medplum put 'Patient?identifier=<exampleMrn>'  <patientResource>
```

```ts
curl -X PUT 'https://api.medplum.com/fhir/R4/Patient?identifier=<exampleMrn>' \
  -H 'authorization: Bearer $ACCESS_TOKEN' \
  -H 'content-type: application/fhir+json' \
  -d '<patientResource>'
```

### Create the ServiceRequest

Creating a new [`ServiceRequest`](/content/docs/api/fhir/resources/servicerequest/index.html) also has some nuance to it. [`ServiceRequests`](/content/docs/api/fhir/resources/servicerequest/index.html) in this context can be thought of as a "requisition for a lab test" and the `ServiceRequest.code` specifies _what test panel_ is being ordered. Most labs will have a concept of a test menu and that should indicate which labs should be run for this service request.

Note that there are many fields on the requisition, and filling them in with the right data is crucial. This example is minimal for clarity.

```ts
import { createReference } from '@medplum/core';
import type { ServiceRequest } from '@medplum/fhirtypes';

const serviceRequestData: ServiceRequest = {
  resourceType: 'ServiceRequest',
  status: 'active',
  intent: 'order',
  subject: createReference(patient), // link this ServiceRequest to the Patient
  code: {
    coding: [
      {
        system: 'https://samplelab.com/tests',
        code: 'SAMPLE_SKU',
      },
    ],
  },
};

const serviceRequest = await medplum.createResource(serviceRequestData);
console.log('Service Request', serviceRequest.id);
```

If you are using the [hosted Medplum service](https://app.medplum.com/) you can see your [`ServiceRequest`](/content/docs/api/fhir/resources/servicerequest/index.html) objects [here](https://app.medplum.com/ServiceRequest). Similarly, you can see [`Patients`](/content/docs/api/fhir/resources/patient/index.html) [here](https://app.medplum.com/Patient).

## Creating the Diagnostic Report

Once the lab test has been completed and the specimens analyzed, it is time to create a diagnostic report - but it is really important to link that diagnostic report back to the [`Patient`](/content/docs/api/fhir/resources/patient/index.html) and the corresponding [`ServiceRequest`](/content/docs/api/fhir/resources/servicerequest/index.html).

To get this to be linked up, you'll need to have the identifiers for the [`Patient`](/content/docs/api/fhir/resources/patient/index.html) and [`ServiceRequest`](/content/docs/api/fhir/resources/servicerequest/index.html) that were created in the previous section.

You can then create a diagnostic report using the function below.

### Create the Observations

```ts
import type { Observation } from '@medplum/fhirtypes';

// Create two observations from the array
const observationData: Observation[] = [
  {
    resourceType: 'Observation',
    basedOn: [createReference(serviceRequest)], // Connect this Observation to the ServiceRequest
    subject: createReference(patient), // Connect this Observation to the Patient
    status: 'preliminary',
    code: {
      coding: [
        {
          system: 'https://samplelabtests.com/tests',
          code: 'A1c',
          display: 'A1c',
        },
      ],
    },
    valueQuantity: {
      value: 5.7,
      unit: 'mg/dL',
      system: UCUM,
      code: 'mg/dL',
    },
  },
  {
    resourceType: 'Observation',
    basedOn: [createReference(serviceRequest)], // Connect this Observation to the ServiceRequest
    subject: createReference(patient), // Connect this Observation to the Patient
    status: 'preliminary',
    code: {
      coding: [
        {
          system: 'https://samplelabtests.com/tests',
          code: 'blood_glucose',
          display: 'Blood Glucose',
        },
      ],
    },
    valueQuantity: {
      value: 100,
      unit: 'mg/dL',
      system: UCUM,
      code: 'mg/dL',
    },
  },
];

// Map through the observation data to create all the observations
const observations = await Promise.all(observationData.map(async (data) => medplum.createResource(data)));

for (const observation of observations) {
  console.log('Created Observation', observation.id);
}
```

### Create Report

```ts
import type { DiagnosticReport } from '@medplum/fhirtypes';

const reportData: DiagnosticReport = {
  resourceType: 'DiagnosticReport',
  basedOn: [createReference(serviceRequest)], // Connect this DiagnosticReport to the ServiceRequest
  subject: createReference(patient), // Connect this DiagnosticReport to the Patient,
  status: 'preliminary',
  code: {
    coding: [
      {
        system: 'https://samplelab.com/testpanels',
        code: 'SAMPLE_SKU',
      },
    ],
  },
  result: observations.map(createReference), // Create an array of references to the relevant observations
};

const report = await medplum.createResource(reportData);
console.log('Created Report', report.id);
```

This will create a [`DiagnosticReport`](/content/docs/api/fhir/resources/diagnosticreport/index.html) that is linked to the [`ServiceRequest`](/content/docs/api/fhir/resources/servicerequest/index.html) and to the [`Patient`](/content/docs/api/fhir/resources/patient/index.html). If you are using hosted Medplum, you can view all [`DiagnosticReports`](/content/docs/api/fhir/resources/diagnosticreport/index.html) [here](/content/docs/api/fhir/resources/diagnosticreport/index.html).

## Next Steps

Now that you have created and linked your FHIR resources, you can:

- **Search** for these resources using [FHIR Search](/content/docs/search/basic-search/index.html).
- **Automate** workflows using [Bots](/content/docs/bots/index.html).
- **Visualize** the data in a [React Application](/content/docs/react/index.html).

## Conclusion

Hopefully this simple lab workflow, "ordering a lab" and "getting a lab report" was a good beginner illustration on getting started with FHIR. We welcome your feedback. Please feel free to file issues or submit pull requests.

This sample is based on a service where data is hosted on Medplum, but for those who need the data stored on premise, we do support self-hosting the backend.
