Skip to content

Add a page that fetches FHIR data

Goal: build a "Patient Summary" page that lists the current patient's recent observations.

Prerequisites:

  • A scaffolded app (orion init).
  • A configured sandbox tenant.
  • Comfort with TypeScript and React.

Steps

  1. Scaffold the page. The CLI writes a manifest entry under extensions.pages[] and a starter src/pages/PatientSummary.tsx:

    bash
    orion generate page patient-summary --path /patient-summary --layout app
  2. Declare the SMART scope in orion-app.json. The marketplace reviewer must approve any new scope before it goes live in production. In a sandbox, approved scopes are auto-granted so you can iterate without waiting on review:

    json
    {
      "scope": ["user/Patient.read", "user/Observation.read"]
    }
  3. Read the SMART context in your component. The App Bridge exposes typed FHIR helpers on the bridge instance — bridge.searchResources, bridge.getResource, bridge.fhirFetch, etc. Pair them with usePatient() for the current patient context. The provider auto-hydrates the SMART token on mount, so searchResources works as soon as the bridge is ready:

    tsx
    import { useEffect, useState } from 'react';
    import { useBridge, usePatient } from '@orion-ehr/app-bridge';
    
    type Observation = {
        id: string;
        code: { text: string };
        valueQuantity?: { value: number; unit: string };
    };
    
    type Bundle = { entry?: { resource: Observation }[] };
    
    export default function PatientSummary() {
        const bridge = useBridge();
        const patient = usePatient();
        const [observations, setObservations] = useState<Observation[]>([]);
    
        useEffect(() => {
            if (!bridge || !patient) return;
            bridge.searchResources<Bundle>('Observation', {
                patient: patient.uuid,
                _count: 10,
                _sort: '-date',
            }).then((bundle) => {
                setObservations((bundle.entry ?? []).map((e) => e.resource));
            });
        }, [bridge, patient]);
    
        return (
            <div>
                <h1>Recent observations</h1>
                <ul>
                    {observations.map((o) => (
                        <li key={o.id}>
                            {o.code.text}: {o.valueQuantity?.value} {o.valueQuantity?.unit}
                        </li>
                    ))}
                </ul>
            </div>
        );
    }

    For endpoints not covered by the typed helpers (Patient/$everything, custom search params, repeated query keys), call bridge.fhirFetch(path, init) directly. If you want to plug a third-party FHIR client in instead, read the SMART token off useTokenResponse() and pass it through.

  4. Run dev and open the new route. Navigate to /patient-summary for any patient in your sandbox tenant. The page should render the observation list:

    bash
    orion dev
  5. Validate before publishing. This catches scope mismatches (declared but unused, or used but undeclared), bundle issues, and manifest schema problems:

    bash
    orion validate

Verify

/patient-summary renders for any patient in your sandbox tenant and the observations list populates from the FHIR API.

Phase 2 added R+W support for ServiceRequest, Basic, QuestionnaireResponse, and DocumentReference — apps whose manifest scopes declare write permission can POST/PUT these resources through bridge.createResource / bridge.updateResource (or bridge.fhirFetch directly).

Documents @orion-ehr/cli v0.0.15 — released under the MIT License.