08 / Healthcare

FHIR R4 patient explorer

Synthetic data · HAPI sandbox

A read-only window onto a public FHIR R4 test server seeded with synthetic records. No real patient data is involved, nothing is persisted, and nothing beyond request metadata is logged.

Patients

    Run a search to list matching patients.

    Patient summary

    Select a patient to load the summary: demographics, counts, active conditions, and recent vital signs.

    Under the hood

    OpenAPI Source
    $ waiting for the first search
    The DTO the function returned
    
              

    How This Demo Is Built

    The same shape as the rest of the site: static HTML in front, a small C# function behind CloudFront, and the contract written before the code.

    Data source
    The public HAPI FHIR R4 test server, which holds only synthetic records and is wiped and repopulated from time to time, so nothing here depends on a particular patient id. The base URL is configuration; the SMART Health IT sandbox is the one-variable fallback when HAPI is down. The function reads the server's CapabilityStatement once per instance to confirm the resources and search parameters the explorer needs are supported.
    API
    Five read-only endpoints under /api/fhir, specified in the same OpenAPI document as the Experience API: patient search, patient summary, the raw bundle behind a summary, the capability subset, and a health check. C# on .NET 10, run on AWS Lambda (arm64) behind this distribution. The browser never talks to the sandbox; the function is the boundary, and only the raw-bundle endpoint passes FHIR JSON through.
    FHIR handling
    The Firely SDK parses every resource into typed objects. A summary reads the Patient, then runs four bounded searches at once: conditions, vital-sign observations, and _summary=count for encounters and observations, following link[rel=next] up to five pages each. Mappers read only the fields US Core makes mandatory or must-support, split conditions on clinicalStatus, prefer SNOMED CT or ICD-10-CM codings, and pick vital signs by LOINC code, with blood pressure carrying its systolic and diastolic components.
    Resilience
    The public sandbox is sometimes slow. Every upstream call has a six-second attempt timeout, two retries with exponential backoff and jitter, a circuit breaker, and a 22-second total budget under CloudFront's 30-second origin limit. A timeout or server error comes back as an RFC 9457 problem (504 or 502) that the page turns into a plain message, never a blank screen.
    Caching and limits
    Responses carry an ETag and Cache-Control, and CloudFront caches on the path plus the three search parameters, so a repeated request is answered at the edge; the panel above shows the X-Cache header and labels a hit's timings as those of the original request. A per-address budget in the function's memory answers 429 past sixty requests in ten minutes. No cookies, no analytics, no PHI, nothing stored.
    Front end
    This page is plain HTML with one deferred script of its own, fhir.js, and no dependencies, under the site's Content Security Policy (no inline script or style). The avatar colours, the pills, and the log block are classes in the shared stylesheet; the layout stacks on a phone and splits on a desktop.
    Read the source on GitHub Back to the portfolio