An open API service indexing awesome lists of open source software.

https://github.com/dnlbox/fhir-capability-analyzer

CLI and library for fetching, analyzing, and comparing FHIR server CapabilityStatements. Profile detection for US Core, UK Core, AU Core, IPS, ISiK and more.
https://github.com/dnlbox/fhir-capability-analyzer

capability-statement cli fhir fhir-r4 fhir-r4b fhir-r5 health-interoperability healthcare hl7 ips r4b typescript us-core

Last synced: about 1 month ago
JSON representation

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

Awesome Lists containing this project

README

          

# fhir-capability-analyzer

[![CI](https://github.com/dnlbox/fhir-capability-analyzer/actions/workflows/ci.yml/badge.svg)](https://github.com/dnlbox/fhir-capability-analyzer/actions/workflows/ci.yml)
[![CodeQL](https://github.com/dnlbox/fhir-capability-analyzer/actions/workflows/codeql.yml/badge.svg)](https://github.com/dnlbox/fhir-capability-analyzer/actions/workflows/codeql.yml)
[![npm](https://img.shields.io/npm/v/fhir-capability-analyzer)](https://www.npmjs.com/package/fhir-capability-analyzer)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)

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

```bash
# 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

```txt
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

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

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

## CLI reference

### `analyze `

Analyze a CapabilityStatement from a URL or local JSON file.

```bash
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 `

Compare two FHIR servers' capabilities.

```bash
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:

```bash
# 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

```typescript
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

```md
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](https://confluence.hl7.org/display/FHIR/Using+the+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`](https://www.npmjs.com/package/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`](https://github.com/dnlbox/fhir-resource-diff) | Validate, diff, and compare individual FHIR JSON resources |
| [`fhir-test-data`](https://github.com/dnlbox/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:**

```bash
# 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

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

### Common scripts

| Script | Purpose |
|--------|---------|
| `pnpm cli -- analyze ` | 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

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

## Links

- [Documentation](https://dnlbox.github.io/fhir-capability-analyzer/)
- [npm](https://www.npmjs.com/package/fhir-capability-analyzer)
- [GitHub](https://github.com/dnlbox/fhir-capability-analyzer)
- [FHIR specification](https://hl7.org/fhir/)