MongoDB Developer
Atlas
plus
Sign in to follow topics
MongoDB Developer Centerchevron-right
Developer Topicschevron-right
Productschevron-right
Atlaschevron-right

How to Build a Healthcare Interoperability Microservice Using FHIR and MongoDB

Paul Claret14 min read • Published Oct 17, 2023 • Updated Oct 17, 2023
JavaScriptAtlas
Facebook Icontwitter iconlinkedin icon
Rate this tutorial
star-empty
star-empty
star-empty
star-empty
star-empty

How to Build a Healthcare Interoperability Microservice Using FHIR and MongoDB

Interoperability refers to a system’s or software's capability to exchange and utilize information. Modern interoperability standards, like Fast Healthcare interoperability Resources (or FHIR), precisely define how data should be communicated. Like most current standards, FHIR uses REST APIs which are set in JSON format. However, these standards do not set how data should be stored, providing software vendors with flexibility in managing information according to their preferences.
This is where MongoDB's approach comes into play — data that is accessed together should be stored together. The compatibility between the FHIR’s resource format and MongoDB's document model allows the data to be stored exactly as it should be communicated. This brings several benefits, such as removing the need for any middleware/data processing tool which decreases development complexity and accelerates read/write operations.
Additionally, MongoDB can also allow you to create a FHIR-compliant Atlas data API. This benefits healthcare providers using software vendors by giving them control over their data without complex integrations. It reduces integration complexity by handling data processing at a platform level. MongoDB's app services also offer security features like authentication. This, however, is not a full clinical data repository nor is it meant to replace one. Rather, this is yet another integration capability that MongoDB has.
In this article, we will walk you through how you can expose the data of FHIR resources through Atlas Data API to two different users with different permissions.

Scenario

  • Dataset: We have a simple dataset where we have modeled the data using FHIR-compliant schemas. These resources are varied: patients, locations, practitioners, and appointments.
  • We have two users groups that have different responsibilities:
    • The first is a group of healthcare providers. These individuals work in a specific location and should only have access to the appointments in said location.
    • The second is a group that works at a healthcare agency. These individuals analyze the appointments from several centers. They should not be able to look at personal identifiable information (or PII).

Prerequisites

Step 1: Insert FHIR documents into the database

Clone this GitHub repository on your computer.
  • Add your connection string on the config.py file. You can find it by following the instructions in our docs.
  • Execute the files: locGen.py,pracGen.py, patientGen.py, and ProposedAppointmentGeneration.py in that order.
Note: The last script will take a couple of minutes as it creates the appointments with the relevant information from the other collections.
Before continuing, you should check that you have a new “FHIR” database along with four collections inside it:
  • Locations with 22 locations
  • Practitioners with 70 documents
  • Patients with 20,000 documents
  • Appointments with close to 7,000 documents

Step 2: Create an App Services application

After you’ve created a cluster and loaded the sample dataset, you can create an application in Atlas App Services.
Follow the steps to create a new App Services application if you haven’t done so already.
I used the name “FHIR-search” and chose the cluster “FHIR” that I’ve already loaded the sample dataset into.
Create a MongoDB App Services Application
After you’ve created the App Services application, navigate to the HTTPS endpoints on the left side menu and click the Data API tab. Then:
  • Click the button “add an endpoint.”.
  • Name the route “/appointment.”
  • Enable the endpoint.
  • Choose the “Get” HTTP method.
  • Enable “respond with result.”
Add an Appointments Endpoint
  • Select “+ New function” and name it. I named it “Appointment,” for example.
  • Copy paste the “Appointment” function from GitHub or from below.
  • Make sure to change the fake URL in said function with the one that was just created from your HTTPS endpoint.
Add Authentication to the Endpoint Function
  • Enable both “Fetch Custom User Data” and “Create User Upon Authentication.”
  • Lastly, save the draft and deploy it.
Publish the Endpoint Function
Now, your API endpoint is ready and accessible! But if you test it, you will get the following authentication error since no authentication provider has been enabled.
Side note: To view the result without any security, you can go into your function, then go to the settings tab and set the authentication to system. However, this will treat any request as if it came from the system, so proceed with caution.

Step 3.1: Enable JWT-based authentication

FHIR emphasizes the importance of secure data exchange in healthcare. While FHIR itself doesn't define a specific authentication protocol, it recommends using OAuth for web-centric applications and highlights the HL7 SMART App Launch guide for added context. This focus on secure authentication aligns with MongoDB Atlas's provision for JWT (JSON Web Tokens) as an authentication method, making it an advantageous choice when building FHIR-based microservices.
Then, to add authentication, navigate to the homepage of the App Services application. Click “Authentication” on the left-hand side menu and click the EDIT button of the row where the provider is Custom JWT Authentication.
Enable JWT Authentication for the Endpoint
JWT (JSON Web Token) provides a token-based authentication where a token is generated by the client based on an agreed secret and cryptography algorithm. After the client transmits the token, the server validates the token with the agreed secret and cryptography algorithm and then processes client requests if the token is valid.
In the configuration options of the Custom JWT Authentication, fill out the options with the following:
  • Enable the Authentication Provider (Provider Enabled must be turned on).
  • Keep the verification method as is (manually specify signing keys).
  • Keep the signing algorithm as is (HS256).
  • Add a new signing key.
    • Provide the signing key name.
      • For example, APITestJWTSigningKEY
    • Provide the secure key content (between 32 and 512 characters) and note it somewhere secure.
      • For example, FipTEgYJ6WfUEhCJq3e@pm8-TkE9*UZN
  • Add two fields in the metadata fields.
    • The path should be metadata.group and the corresponding field should be group.
    • The path should be metadata.name and the corresponding field should be name.
  • Keep the audience field as is (empty).
Below, you can find how the JWT Authentication Provider form has been filled accordingly.
JWT Authentication Provider Example
Save it and then deploy it.
After it’s deployed, you can see the secret that has been created in the App Services Values. It’s accessible on the left side menu by clicking “Values.”
App Services Secret Values

Step 3.2: Test JWT authentication

Now, we need an encoded JWT to pass it to App Services Data API to authenticate and consequently access the underlying data.
You can have a separate external authentication service that can provide a signed JWT that you can use in App Services authentication. However, for the sake of simplicity, we’ll generate our own fake JWTs through jwt.io.
These are the steps to generate an encoded JWT:
  • Visit jwt.io.
  • On the right-hand side in the section Decoded, we can fill out the values. On the left-hand side, the corresponding Encoded JWT will be generated.
  • In the Decoded section:
    • Keep the header section the same.
    • In the Payload section, set the following fields:
      • Sub
        • Represents the owner of the token
        • Provide value unique to the user
      • Metadata
        • Represents metadata information regarding this token and can be used for further processing in App Services
        • We have two sub fields here
          • Name
            • Represents the username of the client that will initiate the API request
            • Will be used as the username in App Services
          • Group
            • Represents the group information of the client that we’ll use later for rule-based access
      • Exp
        • Represents when the token is going to expire
        • Provides a future time to keep expiration impossible during our tests
      • Aud
        • Represents the name of the App Services application that you can get from the homepage of your application in App Services
    • In the Verify Signature section:
Below, you can find how the values have been filled out in the Decoded section and the corresponding Encoded JWT that has been generated.
Generate a JWT for the Example
Copy the generated JWT from the encoded section and pass it to the header section of the HTTP request, as shown below.
We get the following error: “no rule exists for namespace.” This means we were able to authenticate to the application. However, since there were no App Services rules defined, we were not able to access any data.
Even though the request is not successful due to the no rule definition, you can check out the App Users page to list authenticated users, as shown below. user01 was the name of the user that was provided in the metadata.name field of the JWT.
Application Users in App Services
Side note: If you get an error like the one below, then please double-check all JWT payload parameters, and that the value on the signature is indeed the same as the one in the JWT authentication in Atlas.

Step 4.1: Create a role in App Services Rules

Roles are what determine what the user can and cannot see. By default, there is no role, which means that no one can view any information. This is why we had the error above. However, here, we have the simple scenario where both users need access to the same collection, namely “appointments.” If you want to see how to configure Atlas so that we give access to different collections to each user, as well as some other details of Atlas’ app services RBAC, please check out our tutorial.
Otherwise, let’s create a role that will have access to all of the fields.
  • Navigate to the Rules section on the left-hand side of the menu in App Services.
  • Choose the collection appointments on the left side of the menu.
  • Click readAll on the right side of the menu, as shown below.
Collection Rules for Users

Step 4.2: Create filters in App Services Rules

Let’s reiterate our scenario:
  • We have two user groups that have different responsibilities:
    • The first one is a group of healthcare providers. These individuals work in a specific location and should only have access to the appointments in said location.
    • The second is a group that works at a healthcare agency. These individuals analyze the appointments from several centers. They should not be able to look at Personal Identifiable Information (or PII).
We will configure two filters to account for this.
Let’s start with the healthcare provider. Before doing the actual configuration, we will need to set which location the healthcare provider will be working. To do so, connect to the database with your browser or with MongoDB Compass and copy the name of a random location, as shown below.
FHIR Locations Collection Example
Now that we have the location of our healthcare provider, let’s create the first filter:
  • Let’s navigate back to App Services Rules and select the appointments collection, just like before.
  • Select the Filters tab around the center of the screen.
  • Click on “Add filter.”
    • Name it. For example, we could name it something with the name that you chose above. In our case, it would be "St. Barney clinic practitioner."
    • Add “{ "%%user.data.group": "group01" }” to the “apply when” case.
    • Add “{ "location.display": "<your_locations_name>" }” to the query prompt.
    • Save and deploy.
St. Barney Clinic Practitioner Rule
Let’s do the second user:
  • Click on “Add filter.”
    • Name it. I would suggest something like “healthcare agency.”
    • Add “{ "%%user.data.group": "group02" }” to the “apply when” case.
    • Add the document below to the projection prompt.
    • Save and deploy.
Healthcare Agency Rule
Make sure to create a second JWT token for the healthcare agency with a different metadata.name, metadata.group, and sub.

Step 5: How to query on your appointment FHIR search microservice

In order to fully understand all of the functionalities that this server should have, we will refer ourself to the FHIR documentation. As a demo, this won’t be presenting all of FHIR search capabilities. Instead, we will focus on the basic ones.
In our server, we will be able to respond to two types of inputs. First, there are the regular search parameters that we can see at the bottom of the resources’ page. And second, we will implement the Search Result Parameters that can modify the results of a performed search. Because of our data schema, not all will apply. Hence, not all were coded into the function.
More precisely, we will be able to call the search parameters: actor, date, identifier, location, part-status, patient, practitioner, and status. We can also call the search result parameters: _count, _elements, _sort, _maxresults, and _total, along with the page parameter. Please refer to the FHIR documentation to see how they work.
Make sure to test both users as the response for each of them will be different. Here, you have a couple of examples. To keep it short, I’ll set the page to a single appointment by adding ?_count=1 to the URL.
Healthcare provider:
Healthcare agency:
Please note the difference on the total number of documents fetched as well as the participant.actor.display fields missing for the agency user.

Step 6: How to call the microservice from an application

The calls that were shown up to this point were from API platforms such as Postman or Visual Studio’s REST client. However, for security reasons, when putting this into an application such as a React.js application, then the calls might be blocked by the CORS policy. To avoid this, we need to authenticate our data API request. You can read more on how to manage your user sessions in our docs. But for us, it should be as simple as sending the following request:
This will return something like:
These tokens will allow your application to request data from your FHIR microservice. You will just need to replace the header 'jwtTokenString: {{JWT}}' with 'Authorization: Bearer {{token above}}', like so:
You can find additional information in our docs for authenticating Data API requests.

Summary

In conclusion, interoperability plays a crucial role in enabling the exchange and utilization of information within systems and software. Modern standards like Fast Healthcare Interoperability Resources (FHIR) define data communication methods, while MongoDB's approach aligns data storage with FHIR's resource format, simplifying integration and improving performance.
MongoDB's capabilities, including Atlas Data API, offer healthcare providers and software vendors greater control over their data, reducing complexity and enhancing security. However, it's important to note that this integration capability complements rather than replaces clinical data repositories. In the previous sections, we explored how to:
  • Generate your own FHIR data.
  • Configure serverless functions along with Custom JWT Authentication to seamlessly integrate user-specific information.
  • Implement precise data access control through roles and filters.
  • Call the configured APIs directly from the code.
Are you ready to dive in and leverage these capabilities for your projects? Don't miss out on the chance to explore the full potential of MongoDB Atlas App Services. Get started for free by provisioning an M0 Atlas instance and creating your own App Services application.
Should you encounter any roadblocks or have questions, our vibrant developer forums are here to support you every step of the way.

Facebook Icontwitter iconlinkedin icon
Rate this tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Related
Tutorial

Implement Email/Password Authentication in React


Aug 24, 2022 | 8 min read
Tutorial

Using OpenAI Latest Embeddings In A RAG System With MongoDB


Feb 01, 2024 | 15 min read
Tutorial

Tutorial: Build a Movie Search Application Using Atlas Search


Sep 15, 2023 | 11 min read
Article

How to Build Serverless Applications with SST and MongoDB Atlas


Jan 17, 2024 | 3 min read
Table of Contents