Skip to content

dnlbox/fhir-capability-analyzer

Repository files navigation

fhir-capability-analyzer

CI CodeQL npm License: MIT

A TypeScript CLI and library that answers the question: "What does this FHIR server actually support?"

  • Fetch a CapabilityStatement from any FHIR server URL or local JSON file
  • Summarize resources, interactions, operations, and security in a readable format
  • Detect conformance to international profiles: US Core, UK Core, AU Core, IPS, IPA, SMART App Launch, ISiK, and more
  • Generate a structured analysis report with warnings for common configuration issues
  • Compare two servers' capabilities side by side
  • Output as human-readable text, JSON (CI-friendly), or Markdown

The browser-safe core works in Node.js, Deno, Cloudflare Workers, and browser bundles. The CLI wraps the same core with file I/O and exit codes.

Why this exists

Every FHIR server exposes a CapabilityStatement at /metadata describing every resource, interaction, search parameter, and security mechanism it supports. Reading one by hand is painful: a typical document runs 1,000 to 3,000 lines of deeply nested JSON.

fhir-capability-analyzer does that reading for you: fetch, parse, summarize, and compare, all from the command line. It also detects which international profiles a server declares support for, which is useful when integrating with servers in different countries or healthcare systems.

Quick start

# Analyze a live server
npx fhir-capability-analyzer analyze https://hapi.fhir.org/baseR4

# Analyze a local file
npx fhir-capability-analyzer analyze ./capability.json

# JSON output (CI-friendly, stable schema)
npx fhir-capability-analyzer analyze https://hapi.fhir.org/baseR4 --format json

# Markdown output
npx fhir-capability-analyzer analyze https://hapi.fhir.org/baseR4 --format markdown

# Compare two servers
npx fhir-capability-analyzer compare https://server-a.example.com https://server-b.example.com

# Compare and fail CI if differences found
npx fhir-capability-analyzer compare ./baseline.json https://server.example.com --exit-on-diff

Sample output

Server: HAPI FHIR R4 Test Server
FHIR Version: 4.0.1
Status: active
Formats: application/fhir+json, application/fhir+xml, json, xml

Resources (3)
-------------
Patient                        read, vread, update, patch, delete, history-instance, history-type, create, search-type [7 search params]
Observation                    read, create, update, delete, search-type [4 search params]
Condition                      read, create, update, search-type [3 search params]

Operations (2)
--------------
  $everything
  $validate

Profile Conformance
-------------------
  (No known profiles detected)

Security
--------
  CORS: enabled
  Auth: (none declared)

Installation

# Global CLI
npm install -g fhir-capability-analyzer

# Project dependency (library use)
npm install fhir-capability-analyzer

CLI reference

analyze <source>

Analyze a CapabilityStatement from a URL or local JSON file.

Arguments:
  source              FHIR server URL or path to local JSON file

Options:
  -f, --format        Output format: text | json | markdown  (default: text)
  --bearer-token      Bearer token for OAuth 2.0 protected servers
  -v, --version       Print version
  -h, --help          Show help

Exit codes:
  0  Success, no warnings
  1  Success, but warnings were found (text and markdown modes only)
  2  Fetch or parse error

compare <sourceA> <sourceB>

Compare two FHIR servers' capabilities.

Arguments:
  sourceA             FHIR server URL or local JSON file (baseline)
  sourceB             FHIR server URL or local JSON file (target)

Options:
  -f, --format        Output format: text | json | markdown  (default: text)
  --exit-on-diff      Exit with code 1 when differences are found
  --bearer-token      Bearer token for OAuth 2.0 protected servers
  -h, --help          Show help

Authentication

For OAuth 2.0 protected servers, pass the token via flag or environment variable:

# Via flag
fhir-capability-analyzer analyze https://secure.example.com --bearer-token "$TOKEN"

# Via environment variable (preferred for CI — keeps the token out of shell history)
FHIR_TOKEN=eyJ... fhir-capability-analyzer analyze https://secure.example.com

# Compare two secured servers (same token used for both)
FHIR_TOKEN=eyJ... fhir-capability-analyzer compare https://server-a.example.com https://server-b.example.com

The --bearer-token flag takes precedence over FHIR_TOKEN. Tokens are never written to stdout or included in any output format.

TypeScript library API

import {
  fetchCapabilityStatement,
  parseFromJson,
  analyze,
  compare,
} from "fhir-capability-analyzer";

import { detectProfiles } from "fhir-capability-analyzer/registry";

// Fetch from a live server
const result = await fetchCapabilityStatement("https://hapi.fhir.org/baseR4");

// Fetch from an OAuth 2.0 protected server
const result = await fetchCapabilityStatement("https://secure.example.com", {
  headers: { Authorization: `Bearer ${token}` },
});
if (!result.success) throw new Error(result.error);

// Analyze
const report = analyze(result.capability);
console.log(report.summary.resourceCount); // number of resources
console.log(report.conformance.detectedProfiles); // ProfileConformance[]
console.log(report.warnings); // string[]

// Parse from local JSON (e.g., after fs.readFileSync)
const localResult = parseFromJson(JSON.parse(rawJson));

// Compare two capabilities
const diff = compare(capA, capB);
// diff.added, diff.removed, diff.changed — ComparisonDifference[]

// Profile detection only
const profiles = detectProfiles([
  "http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient",
]);
// [{ url, name, country, standard }]

Profile detection

Detects conformance to known international and national FHIR profiles by matching profile URLs declared in instantiates, implementationGuide, and per-resource profile/supportedProfile fields.

Standard Country Canonical URL prefix
US Core 🇺🇸 us http://hl7.org/fhir/us/core/
UK Core 🇬🇧 uk https://fhir.hl7.org.uk/, https://fhir.nhs.uk/
AU Core 🇦🇺 au http://hl7.org.au/fhir/core/
AU Base 🇦🇺 au http://hl7.org.au/fhir/
CA Baseline 🇨🇦 ca http://hl7.org/fhir/ca/baseline/
IPS 🌍 international http://hl7.org/fhir/uv/ips/
IPA 🌍 international http://hl7.org/fhir/uv/ipa/
SMART App Launch 🌍 international http://fhir-registry.smarthealthit.org/, http://hl7.org/fhir/smart-app-launch/
ISiK 🇩🇪 de https://gematik.de/fhir/isik/, https://gematik.de/fhir/ISiK/
FR Core 🇫🇷 fr http://hl7.org/fhir/fr/core/, https://hl7.fr/ig/fhir/
NL Nictiz 🇳🇱 nl http://nictiz.nl/fhir/
IHE 🌍 international https://profiles.ihe.net/

These are FHIR canonical identifiers. Some canonical URL hosts do not resolve in a browser, but the identifiers still need to be matched exactly when they appear in a CapabilityStatement.

Architecture

src/core/        browser-safe functional core
  types.ts       all shared TypeScript interfaces
  parse.ts       CapabilityStatement → ServerCapability
  fetch.ts       fetch from URL, parse from JSON
  analyze.ts     ServerCapability → AnalysisReport
  compare.ts     ServerCapability × ServerCapability → ComparisonReport

src/registry/    browser-safe profile registry
  profiles.ts    known profile URL patterns
  detect.ts      detectProfiles(urls[]) → ProfileConformance[]

src/formatters/  browser-safe output renderers
  text.ts        human-readable text
  json.ts        stable JSON
  markdown.ts    Markdown tables

src/cli/         Node.js adapter (thin shell over core)
  commands/      analyze.ts, compare.ts

No code under src/core/, src/registry/, or src/formatters/ imports Node.js APIs. This is enforced by TypeScript and tested.

What this tool does NOT do

  • Full StructureDefinition / profile conformance validation — use the HL7 FHIR Validator
  • Profile evaluation beyond URL pattern matching (only checks declared URLs, not resource content)
  • OAuth 2.0 authorization flows — you need to obtain a bearer token separately and pass it via --bearer-token or FHIR_TOKEN
  • IG package resolution or download
  • XML to JSON conversion — use the fhir package

Supported FHIR versions

R4 (4.0.1), R4B (4.3.0), R5 (5.0.0) — auto-detected from the fhirVersion field.

The FHIR TypeScript ecosystem

fhir-capability-analyzer is part of a small family of tools for FHIR developer workflows:

Tool Purpose
fhir-resource-diff Validate, diff, and compare individual FHIR JSON resources
fhir-test-data Generate valid FHIR test data with country-aware identifiers (14 locales)
fhir-capability-analyzer (this package) Fetch, analyze, and compare FHIR server CapabilityStatements

Using them together:

# Check what a server supports before running integration tests
fhir-capability-analyzer analyze https://your-fhir-server.example.com

# Generate test patients and validate them against the FHIR spec
fhir-test-data generate patient --locale uk --seed 42 | \
  fhir-resource-diff validate - --fhir-version R4

# Compare two servers to find differences before a migration
fhir-capability-analyzer compare https://old-server.example.com https://new-server.example.com \
  --exit-on-diff

Development

Prerequisites

  • Node.js >= 20
  • pnpm >= 9

Setup

git clone https://github.com/dnlbox/fhir-capability-analyzer.git
cd fhir-capability-analyzer
pnpm install

Common scripts

Script Purpose
pnpm cli -- analyze <url> Run CLI from source
pnpm test Run tests
pnpm test:watch Run tests in watch mode
pnpm typecheck TypeScript type checking
pnpm lint ESLint
pnpm build Production build (tsup)

Roadmap

  • Authentication support for secured FHIR servers (OAuth 2.0 token injection)
  • --assert flag for CI: fail if a specific profile is not detected

Links

About

CLI and library for fetching, analyzing, and comparing FHIR server CapabilityStatements. Profile detection for US Core, UK Core, AU Core, IPS, ISiK and more.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors