An ephemeral FHIR R4 service for the WellData project, providing session-scoped in-memory FHIR resource storage with HAPI FHIR.
The WellData Ephemeral FHIR Service implements the ephemeral FHIR service concept from the WellData Implementation Guide. It provides:
- Session-scoped storage: Each access token gets its own isolated FHIR resource store
- Token-bound lifecycle: Sessions are tied to JWT access token expiry
- In-memory operation: Fast, ephemeral storage for client-side FHIR operations
- WellData profiles: Serves StructureDefinitions from the WellData Implementation Guide
| Feature | Status |
|---|---|
| In-memory FHIR R4 storage | Implemented |
| Session isolation per access token | Implemented |
| JWT token parsing (jti, sub, exp) | Implemented |
| Automatic session cleanup | Implemented |
| WellData IG profile serving | Implemented |
| Solid pod integration | Implemented (pod URL derived from WebID) |
| Static Questionnaire serving | Implemented (from local files) |
| Token signature validation | Not yet implemented |
The following features are planned for future releases:
- Questionnaire proxy/federation: Support proxying Questionnaires from a remote FHIR server instead of or in addition to local files
- Configurable Questionnaire sources: Allow configuration of multiple Questionnaire sources (local, remote, or combined)
- Questionnaire caching: Cache remote Questionnaires with configurable TTL
Start all services (FHIR server, Solid pod, and demo client):
docker compose up --buildFor development with auto-rebuild on file changes:
docker compose watchServices will be available at:
- Demo client: http://localhost:3001
- FHIR server: http://localhost:8080/fhir
- Solid pod: http://localhost:3000
./mvnw spring-boot:runThe FHIR server will be available at http://localhost:8080/fhir
The demo client is a React application that demonstrates the WellData workflow:
- Login with Solid - Authenticate using Solid OIDC (default: local Solid pod)
- Fill out a health questionnaire - Answer questions about vitals, wellbeing, lifestyle
- Submit responses - Creates a QuestionnaireResponse and linked Observations (with shared timestamp)
- View history - See responses grouped with their related observations
The demo client supports connecting to external Solid providers instead of the local pod:
- Click "Use different Solid provider" on the login screen
- Enter the URL of your Solid provider (e.g.,
https://solidcommunity.net,https://login.inrupt.com) - Click "Login with Solid"
This allows you to use your existing Solid identity with social login providers (Google, etc.) if your Solid provider supports it.
The demo client uses Solid-OIDC with a dynamically generated Client ID Document served at /clientid.jsonld. This document is automatically configured based on the deployment URL, making it work on any host without configuration changes.
The service requires a JWT Bearer token for accessing patient data endpoints. The token is used to scope data to a specific session.
GET /fhir/metadata- CapabilityStatementGET /fhir/StructureDefinition- WellData profilesGET /fhir/ImplementationGuide- Implementation guide metadataGET /fhir/Questionnaire- Questionnaires (shared definitions)
/fhir/Patient/fhir/Observation/fhir/QuestionnaireResponse
# Get a JWT token from your identity provider, then:
curl -H "Authorization: Bearer <your-jwt-token>" http://localhost:8080/fhir/PatientThe service extracts the following claims from the JWT:
jti- Used as session identifier (falls back to token hash if not present)sub- WebID (e.g.,https://roland.solidcommunity.net/profile/card#me) used to derive the Solid pod URLexp- Expiry time (session is cleaned up after this time)
curl http://localhost:8080/fhir/metadatacurl http://localhost:8080/fhir/StructureDefinitioncurl -H "Authorization: Bearer <token>" http://localhost:8080/fhir/Patientcurl -H "Authorization: Bearer <token>" \
"http://localhost:8080/fhir/Observation?subject=Patient/example-welldata-patient"curl -X POST http://localhost:8080/fhir/Patient \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/fhir+json" \
-d '{"resourceType": "Patient", "name": [{"family": "Test", "given": ["User"]}]}'| Resource | Search Parameters |
|---|---|
| Patient | identifier, name, family, given, birthdate |
| Observation | subject, code, date, status, category |
| Questionnaire | identifier, name, title, status |
| QuestionnaireResponse | subject, questionnaire, status, authored, author |
| StructureDefinition | url, name, type, status |
| ImplementationGuide | url, name, status |
┌─────────────────┐ ┌─────────────────────────────────────────┐
│ Client App │────▶│ Ephemeral FHIR Service │
│ │◀────│ │
└─────────────────┘ │ ┌─────────────────────────────────┐ │
│ │ AccessTokenInterceptor │ │
JWT Token ──────▶│ │ - Extract Bearer token │ │
│ │ - Decode JWT (jti, sub, exp) │ │
│ │ - Create/retrieve session │ │
│ └─────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ SessionManager │ │
│ │ - Per-token resource stores │ │
│ │ - Automatic cleanup on expiry │ │
│ └─────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ WellDataResourceProvider │ │
│ │ - Session-scoped CRUD │ │
│ │ - In-memory storage │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘
Configuration is managed via src/main/resources/application.yaml:
server:
port: 8080
welldata:
testdata:
path: classpath:testdata
ig:
url: https://github.com/GIDSOpenStandaarden/welldata-implementation-guide/releases/download/v0.1.1/welldata-0.1.1.tgz- Java 21
- Maven 3.9+
- Docker (optional)
./mvnw clean package./mvnw testsrc/main/java/nl/gidsopenstandaarden/welldata/fhir/
├── Application.java # Spring Boot entry point
├── config/
│ └── WellDataRestfulServer.java # HAPI FHIR server configuration
├── context/
│ └── AccessTokenContext.java # ThreadLocal token context
├── interceptor/
│ └── AccessTokenInterceptor.java # JWT extraction and session setup
├── provider/
│ ├── WellDataResourceProvider.java # Base session-scoped provider
│ ├── PatientResourceProvider.java
│ ├── ObservationResourceProvider.java
│ ├── QuestionnaireResourceProvider.java
│ ├── QuestionnaireResponseResourceProvider.java
│ ├── StructureDefinitionResourceProvider.java
│ └── ImplementationGuideResourceProvider.java
└── service/
├── JsonDataLoader.java # Test data loading
├── IgPackageLoader.java # IG package loading
└── SessionManager.java # Session lifecycle management
This project includes GitHub Actions workflows for continuous integration and deployment.
On every push to main/master or on tags starting with v:
- Builds and tests the FHIR server with Maven
- Builds Docker images for both FHIR server and demo client
- Pushes images to GitHub Container Registry (ghcr.io)
Deployment to Kubernetes is triggered automatically on pushes to main or version tags. Configure the following in your GitHub repository:
Secrets:
KUBECONFIG- Base64-encoded kubeconfig file for cluster access
Variables:
KUBERNETES_NAMESPACE- Target namespace (default:default)DEFAULT_SOLID_PROVIDER- Solid provider URL (default:https://solidcommunity.net)INGRESS_ENABLED- Enable ingress (default:false)INGRESS_CLASS- Ingress class name (default:nginx)APP_HOSTNAME- Hostname for ingress (default:welldata.example.com)APP_URL- Full URL for environment link
A Helm chart is provided for deploying to Kubernetes clusters.
helm install welldata-ephemeral-fhir ./chart/welldata-ephemeral-fhir-servicehelm install welldata-ephemeral-fhir ./chart/welldata-ephemeral-fhir-service \
--set demoClient.defaultSolidProvider=https://solidcommunity.net \
--set demoClient.service.type=LoadBalancer| Parameter | Description | Default |
|---|---|---|
fhirServer.replicaCount |
Number of FHIR server replicas | 1 |
fhirServer.image.repository |
FHIR server image | gidsopenstandaarden/welldata-ephemeral-fhir-service |
fhirServer.image.tag |
FHIR server image tag | latest |
demoClient.enabled |
Enable demo client | true |
demoClient.defaultSolidProvider |
Default Solid provider URL | https://solidcommunity.net |
demoClient.service.type |
Demo client service type | ClusterIP |
demoClient.ingress.enabled |
Enable ingress for demo client | false |
See chart/welldata-ephemeral-fhir-service/values.yaml for all available options.
- WellData Implementation Guide - FHIR profiles and specifications
- HAPI FHIR - FHIR implementation library
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.