IBM FHIR Server on the Raspberry Pi 4
By Robin Arnold | Published September 13, 2019
Usage
This installation is for curiosity only and should not be used with PHI, only synthetic test data. Production instances require additional hardening which is outside the scope of this guide.
The default password used throughout is change-password
and this is configured as clear-text in the configuration files to make it even more obvious that it should be changed as part of any hardening. Refer to the FHIRServerUsersGuide for more details.
Introduction
The IBM FHIR Server runs as a web application in the Open Liberty application server. By default persistence is provided with a Derby database, but it can also be configured to use IBM Db2 on Cloud. This example shall use the default Derby instance.
Component | Details |
---|---|
Hardware | Raspberry Pi 4 |
Memory | 4GB |
OS | Raspbian (Buster) |
Storage | 64GB microSD |
Java | openjdk11 |
Apache Maven | 3.6.1 |
Application Server | Open Liberty 19.0.0.8 |
HTTPS Port | 9443 |
Default user | fhiruser |
Default password | change-password |
Set up your Raspberry Pi 4 (4GB model) using Raspbian (https://www.raspberrypi.org/downloads/).
TIP: Under load, the Raspberry Pi 4 CPU throttles when it reaches a critical temperature, so a case with cooling is recommended. Without naming products, an aluminum case which acts as a heat sink could be a good choice. The CPU definitely throttles during the build using the official (plastic) Raspberry Pi 4 case.
Development Environment and Prerequisites
To build we need three things:
- openjdk11 (already available)
- Apache Maven
- Access to the internet (for Maven dependencies)
Install Maven
You can use apt-get to install Apache Maven but if you want to avoid all the dependencies which come along with it, just grab the binary release and unpack it
OPTION A:
sudo apt-get install maven
OPTION B:
wget https://www-us.apache.org/dist/maven/maven-3/3.6.1/binaries/apache-maven-3.6.1-bin.tar.gz -P /tmpsudo mkdir -p /opt/tools && cd /opt/tools && tar xzvf /tmp/apache-maven-3.6.1-bin.tar.gz
If installing Maven manually, add it to your PATH:
# Add Maven to PATHexport PATH="/opt/tools/apache-maven-3.6.1/bin:${PATH}"
Check
pi@raspberrypi:~/git/FHIR $ mvn -versionApache Maven 3.6.1 (d66c9c0b3152b2e69ee9bac180bb8fcc8e6af555; 2019-04-04T15:00:29-04:00)Maven home: /opt/tools/apache-maven-3.6.1Java version: 11.0.3, vendor: Raspbian, runtime: /usr/lib/jvm/java-11-openjdk-armhfDefault locale: en_US, platform encoding: UTF-8OS name: "linux", version: "4.19.66-v7l+", arch: "arm", family: "unix"
Environment
Component | Details |
---|---|
Liberty Home | /opt/ibm/fhir-server/wlp |
JAVA_HOME | /usr/lib/jvm/java-11-openjdk-armhf |
Building
Set up your development environment and clone the repository:
mkdir -p ~/git && cd ~/git && git clone https://github.com/LinuxForHealth/FHIR.git
Now you should be ready to build:
cd ~/git/FHIRmvn clean install -f fhir-parent/pom.xml
Be patient. A lot of unit tests are executed, including processing a number of the FHIR specification examples in various contexts which is fairly CPU intensive. Unit tests in the fhir-persistence-jdbc project use a functional schema deployed in a Derby database, exercising the bulk of the persistence code except for the REST layer.
Some exceptions from negative tests may appear in the build log. As long as the build completes, these shouldn’t be a concern. Success should look like this:
[INFO] Reactor Summary for IBM FHIR Server FHIR 4.0.0-SNAPSHOT:[INFO][INFO] IBM FHIR Server ...................... SUCCESS [ 8.537 s][INFO] fhir-core .......................................... SUCCESS [ 7.478 s][INFO] fhir-task-api ...................................... SUCCESS [ 0.583 s][INFO] fhir-task-core ..................................... SUCCESS [ 9.217 s][INFO] fhir-database-utils ................................ SUCCESS [ 16.877 s][INFO] fhir-config ........................................ SUCCESS [ 12.278 s][INFO] fhir-audit ......................................... SUCCESS [ 13.421 s]
Installation
The above build creates an installable artifact:
~/git/FHIR/fhir-install/target/fhir-server-distribution.zip
Unpack the archive into a working directory:
mkdir -p ~/unpack && cd ~/unpack && unzip ~/git/FHIR/fhir-install/target/fhir-server-distribution.zip
Decide where you want to install. As this isn’t a production server, installing it under the pi user is convenient.
mkdir -p ~/runtime/fhir-server && sh ~/unpack/fhir-server-dist/install.sh ~/runtime/fhir-server
Check that the Liberty runtime was installed correctly:
~/runtime/fhir-server/wlp/bin/server status fhir-serverServer fhir-server is not running.
The default configuration uses a 4GB heap size which is too large for the Pi. Edit the jvm.options file and reduce the memory footprint using -Xmx1024M and -Xms1024M:
pi@raspberrypi:~ $ vi ~/runtime/fhir-server/wlp/usr/servers/fhir-server/jvm.options...grep -- -Xm ~/runtime/fhir-server/wlp/usr/servers/fhir-server/jvm.options-Xms1024M-Xmx1024M
Start the server (the first startup takes some time):
~/runtime/fhir-server/wlp/bin/server start fhir-serverStarting server fhir-server.Server fhir-server started with process ID 1234.
Smoke Test
Run a basic connectivity check. This is a primitive check to ensure that the application server is accessible and that the FHIR web application is running:
sh ~/unpack/fhir-server-dist/fhirSmokeTest.sh localhost 9443Checking if server localhost is accessible on port 9443 ... OK!Checking FHIR server signature... OK!Checking FHIR API version... OK!Success! All checks passed.
Clean up
rm -fr ~/unpack/fhir-server-distrm -f /tmp/apache-maven-3.6.1-bin.tar.gz
Create a Patient Resource
Create a new patient resource using the following POST. The FHIR server will allocate a unique logical identifier (UUID):
curl -k \-H 'Content-Type: application/json' \-u 'fhiruser:change-password' 'https://localhost:9443/fhir-server/api/v4/Patient' -d '{"resourceType" : "Patient","active" : true,"name" : [ {"family" : "Ortiz","given" : [ "David" ]
The FHIR server should respond with a 201 Created status:
HTTP/2 201location: https://localhost:9443/fhir-server/api/v4/Patient/041786ad-d6a1-42ea-bf47-4dd8eb08a5fc/_history/1etag: W/"1"last-modified: 2019-09-12T19:22:02.159503Zdate: Thu, 12 Sep 2019 19:22:05 GMTcontent-length: 0content-language: en-US
Use the location:
value returned from your POST to read back the resource:
Command (example):
curl --silent -k -H 'Accept: application/json' -u 'fhiruser:change-password' 'https://localhost:9443/fhir-server/api/v4/Patient/041786ad-d6a1-42ea-bf47-4dd8eb08a5fc' | python -m json.tool
Remember to use the patient logical id returned as the location: header in your POST - if you try to use
041786ad-d6a1-42ea-bf47-4dd8eb08a5fc
the response status will be Not Found.
Output:
{"active": true,"gender": "male","id": "041786ad-d6a1-42ea-bf47-4dd8eb08a5fc","meta": {"lastUpdated": "2019-09-12T19:22:02.159503Z","versionId": "1"},"name": [
Now we can update the resource using a PUT (David => Dave). Again, it is important to use the logical ids from your example, not the values shown here. This includes the “id” field in the body, which should match the logical id of the URL:
curl -k -i \-X PUT \-H 'Content-Type: application/json' \-u 'fhiruser:change-password' 'https://localhost:9443/fhir-server/api/v4/Patient/041786ad-d6a1-42ea-bf47-4dd8eb08a5fc' -d '{"active": true,"gender": "male","id": "041786ad-d6a1-42ea-bf47-4dd8eb08a5fc","meta": {
Response:
HTTP/2 200location: https://localhost:9443/fhir-server/api/v4/Patient/041786ad-d6a1-42ea-bf47-4dd8eb08a5fc/_history/2etag: W/"2"last-modified: 2019-09-12T19:46:24.656131Zdate: Thu, 12 Sep 2019 19:46:26 GMTcontent-length: 0content-language: en-US
Note the location: has now changed to indicate the new version is 2.
Retrieve the latest version:
curl --silent -k -H 'Accept: application/json' -u 'fhiruser:change-password' 'https://localhost:9443/fhir-server/api/v4/Patient/041786ad-d6a1-42ea-bf47-4dd8eb08a5fc' | python -m json.tool
Response:
curl --silent -k -H 'Accept: application/json' -u 'fhiruser:change-password' 'https://localhost:9443/fhir-server/api/v4/Patient/041786ad-d6a1-42ea-bf47-4dd8eb08a5fc' | python -m json.tool{"active": true,"gender": "male","id": "041786ad-d6a1-42ea-bf47-4dd8eb08a5fc","meta": {"lastUpdated": "2019-09-12T19:46:24.656131Z","versionId": "2"},
Note that the given name is “Dave”.
To see a previous version, perform a vread:
curl --silent -k -H 'Accept: application/json' -u 'fhiruser:change-password' 'https://localhost:9443/fhir-server/api/v4/Patient/041786ad-d6a1-42ea-bf47-4dd8eb08a5fc/_history/1' | python -m json.tool
Response:
{"active": true,"gender": "male","id": "041786ad-d6a1-42ea-bf47-4dd8eb08a5fc","meta": {"lastUpdated": "2019-09-12T19:22:02.159503Z","versionId": "1"},"name": [
In version 1, we see that the given name is the original value of “David”.
All the versions of the resource can be read using a history read operation:
curl --silent -k -H 'Accept: application/json' -u 'fhiruser:change-password' 'https://localhost:9443/fhir-server/api/v4/Patient/041786ad-d6a1-42ea-bf47-4dd8eb08a5fc/_history' | python -m json.tool
The response is a FHIR bundle resource containing both versions of the Patient. Note the name change from David (version 1) to Dave (version 2):
{"entry": [{"fullUrl": "https://localhost:9443/fhir-server/api/v4/Patient/041786ad-d6a1-42ea-bf47-4dd8eb08a5fc","request": {"method": "PUT","url": "Patient/041786ad-d6a1-42ea-bf47-4dd8eb08a5fc"},"resource": {