Secondary Use FHIR Server Implementation Guide
0.1.0 - ci-build

Secondary Use FHIR Server Implementation Guide - Local Development build (v0.1.0) built by the FHIR (HL7® FHIR® Standard) Build Tools. See the Directory of published versions

Getting Started

Getting Started

Container Quick Start

From the repository root, start the synthetic source and privacy adapter with Docker Compose:

mkdir -p secrets
cp config/demo.properties config/instance.properties
: > config/opt-outs.txt
docker compose up --build -d
curl -fsS http://127.0.0.1:8080/health

Open http://127.0.0.1:8080/ for the bundled query UI. The adapter FHIR base is http://127.0.0.1:8080/fhir; the mock source runs inside the container and is not published. These examples use the synthetic demo. For an external hospital source, follow docs/HOSPITAL.md in the repository.

1. Create the Group for feasibility

Verkennen creates a criteria-based Group and reads its protected quantity after activation. Export reuses that same Group. The count is the number of people; clinical resource counts come from completed export manifests.

Create /tmp/cohort.json for a synthetic female Crohn cohort. This command can be copied as-is from the repository root:

cat > /tmp/cohort.json <<'JSON'
{
  "resourceType": "Group",
  "meta": { "profile": ["http://hl7.org/fhir/uv/bulkdata/StructureDefinition/bulk-cohort-group"] },
  "modifierExtension": [
    { "url": "http://hl7.org/fhir/uv/bulkdata/StructureDefinition/member-filter", "valueExpression": { "language": "application/x-fhir-query", "expression": "Condition?code=34000006" } },
    { "url": "http://hl7.org/fhir/uv/bulkdata/StructureDefinition/member-filter", "valueExpression": { "language": "application/x-fhir-query", "expression": "Patient?gender=female" } }
  ],
  "type": "person",
  "actual": false,
  "name": "IBD cohort"
}
JSON

Submit it:

curl -i -fsS \
  -H 'Accept: application/fhir+json' \
  -H 'Content-Type: application/fhir+json' \
  --data-binary @/tmp/cohort.json \
  'http://127.0.0.1:8080/fhir/Group'

The adapter returns 201 Created with a stable Group Location. Read that URL, honoring Retry-After while actual=false:

curl -i '{group-location}'

Activation completes when actual=true. Read quantity and the members-refreshed extension; the Group is reused for export. The legacy request with Prefer: respond-async instead returns 202 and an operation-result URL, but the bundled UI uses the direct Group handle.

In external-source mode Group reads exclude members; small quantities are withheld. Update the Group with actual=false and no members to re-evaluate criteria and opt-outs, keeping its id. The membership refresh time is exposed as an extension.

2. Export one primary type from the same Group

curl -i \
  -H 'Accept: application/fhir+json' \
  -H 'Prefer: respond-async' \
  'http://127.0.0.1:8080/fhir/Group/{group-id}/$export?_type=Observation&_typeFilter=Observation%3Fcode%3Dhttp%3A%2F%2Floinc.org%7C38445-3'

The response is 202 Accepted and includes Content-Location.

3. Poll and Download

curl -fsS '{content-location}'
curl -fsS '{output-url}'

Honor Retry-After while the status is 202. On completion, the first URL returns the Bulk Data manifest as application/json; each output[].url returns FHIR NDJSON. If you add an Accept header to a manifest request, use application/json.

4. Request Minimized Output

Pseudonymization is automatic. For the smaller analytical representation, add _elements:

curl -i \
  -H 'Accept: application/fhir+json' \
  -H 'Prefer: respond-async' \
  'http://127.0.0.1:8080/fhir/Group/{group-id}/$export?_type=Condition&_elements=Condition.subject,Condition.code'

Partial resources carry the standard SUBSETTED tag.