npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

fhir-rest-client

v0.3.2

Published

FHIR R4 TypeScript HTTP SDK — zero runtime dependencies, cross-platform (Browser + Node.js 18+)

Readme

fhir-rest-client

A modern, type-safe FHIR R4 TypeScript HTTP client with zero runtime dependencies.

npm version License

Features

  • Zero Runtime Dependencies — No external packages required at runtime
  • 🌐 Cross-Platform — Works in Browser and Node.js 18+
  • 🔒 Type-Safe — Full TypeScript support with comprehensive type definitions
  • 🔐 Multiple Auth Methods — Bearer token, Client credentials, Password flow, PKCE
  • 💾 Smart Caching — LRU cache with TTL and automatic invalidation
  • 🔄 Auto-Retry — Exponential backoff for transient failures
  • 📦 Auto-Batching — Automatic request batching with configurable windows
  • 🔍 Fluent Query Builder — Type-safe search parameter construction
  • 🔌 WebSocket Subscriptions — Real-time resource updates with auto-reconnect
  • 🪶 Lightweight — Tree-shakeable ESM and CJS builds

Installation

npm install fhir-rest-client

Quick Start

import { FhirClient } from "fhir-rest-client";

// Create a client
const client = new FhirClient({
  baseUrl: "https://fhir.example.com",
  auth: {
    type: "bearer",
    token: "your-access-token",
  },
});

// Read a resource
const patient = await client.read("Patient", "patient-123");
console.log(patient.name);

// Search with query builder
import { SearchParamsBuilder } from "fhir-rest-client";

const params = new SearchParamsBuilder()
  .where("family", "Smith")
  .where("birthdate", "gt2000-01-01")
  .sort("birthdate", "desc")
  .count(10)
  .build();

const bundle = await client.search("Patient", params);

Authentication

Bearer Token

const client = new FhirClient({
  baseUrl: "https://fhir.example.com",
  auth: {
    type: "bearer",
    token: "your-access-token",
  },
});

Client Credentials

const client = new FhirClient({
  baseUrl: "https://fhir.example.com",
  auth: {
    type: "client",
    tokenUrl: "https://auth.example.com/token",
    clientId: "your-client-id",
    clientSecret: "your-client-secret",
  },
});

Password Flow

const client = new FhirClient({
  baseUrl: "https://fhir.example.com",
  auth: {
    type: "password",
    tokenUrl: "https://auth.example.com/token",
    clientId: "your-client-id",
    username: "[email protected]",
    password: "your-password",
  },
});

PKCE (Authorization Code with Proof Key)

import { FhirClient, generatePkceChallenge } from "fhir-rest-client";

const { codeVerifier, codeChallenge } = await generatePkceChallenge();

const client = new FhirClient({
  baseUrl: "https://fhir.example.com",
  auth: {
    type: "pkce",
    tokenUrl: "https://auth.example.com/token",
    authorizeUrl: "https://auth.example.com/authorize",
    clientId: "your-client-id",
    redirectUri: "https://yourapp.com/callback",
    codeVerifier,
    codeChallenge,
  },
});

// After user authorization, exchange code for token
await client.auth.signIn({ code: "authorization-code" });

CRUD Operations

// Create
const newPatient = await client.create("Patient", {
  resourceType: "Patient",
  name: [{ family: "Smith", given: ["John"] }],
});

// Read
const patient = await client.read("Patient", "patient-123");

// Update
patient.telecom = [{ system: "phone", value: "555-1234" }];
const updated = await client.update("Patient", "patient-123", patient);

// Delete
await client.delete("Patient", "patient-123");

// Patch (JSON Patch)
await client.patch("Patient", "patient-123", [
  { op: "replace", path: "/active", value: false },
]);

Search

// Simple search
const results = await client.search("Patient", { family: "Smith" });

// Fluent query builder
import { SearchParamsBuilder } from "fhir-rest-client";

const params = new SearchParamsBuilder()
  .where("family", "Smith")
  .where("birthdate", "gt2000-01-01")
  .where("active", "true")
  .sort("birthdate", "desc")
  .count(20)
  .include("Patient", "organization")
  .revInclude("Observation", "subject")
  .build();

const bundle = await client.search("Patient", params);

// Pagination
if (bundle.link) {
  const nextPage = await client.searchByUrl(
    bundle.link.find((l) => l.relation === "next")?.url,
  );
}

Caching

const client = new FhirClient({
  baseUrl: "https://fhir.example.com",
  cache: {
    enabled: true,
    maxSize: 1000, // Max cached items
    ttl: 300000, // 5 minutes TTL
    invalidateOnMutate: true, // Auto-invalidate on create/update/delete
  },
});

// Reads are cached automatically
const patient1 = await client.read("Patient", "123"); // Cache miss
const patient2 = await client.read("Patient", "123"); // Cache hit

// Updates invalidate cache
await client.update("Patient", "123", updatedPatient); // Cache invalidated
const patient3 = await client.read("Patient", "123"); // Cache miss

Retry & Error Handling

const client = new FhirClient({
  baseUrl: "https://fhir.example.com",
  retry: {
    enabled: true,
    maxRetries: 3,
    baseDelay: 1000, // 1 second
    maxDelay: 30000, // 30 seconds
    factor: 1.5, // Exponential backoff
  },
});

try {
  const patient = await client.read("Patient", "invalid-id");
} catch (error) {
  if (error instanceof ResourceNotFoundError) {
    console.error("Patient not found");
  } else if (error instanceof OperationOutcomeError) {
    console.error("FHIR error:", error.outcome);
  } else if (error instanceof NetworkError) {
    console.error("Network error:", error.message);
  }
}

Auto-Batching

const client = new FhirClient({
  baseUrl: "https://fhir.example.com",
  batch: {
    enabled: true,
    maxBatchSize: 100,
    windowMs: 50, // Batch requests within 50ms window
  },
});

// These requests are automatically batched into a single Bundle
const [patient1, patient2, patient3] = await Promise.all([
  client.read("Patient", "1"),
  client.read("Patient", "2"),
  client.read("Patient", "3"),
]);

WebSocket Subscriptions

import { ClientSubscriptionManager } from "fhir-rest-client";

const subscriptionManager = new ClientSubscriptionManager({
  wsUrl: "wss://fhir.example.com/ws",
  token: "your-token",
  reconnect: true,
  reconnectInterval: 5000,
});

// Subscribe to resource updates
subscriptionManager.on("notification", (event) => {
  console.log("Resource updated:", event.resource);
});

subscriptionManager.on("error", (error) => {
  console.error("Subscription error:", error);
});

await subscriptionManager.connect();

// Subscribe to specific criteria
await subscriptionManager.subscribe({
  resourceType: "Subscription",
  id: "subscription-123",
  criteria: "Observation?status=final",
});

IG Loading (v0.2.0)

Load and browse ImplementationGuide data with built-in caching and ETag support.

import { MedXAIClient } from "fhir-rest-client";

const client = new MedXAIClient({
  baseUrl: "http://localhost:8080",
  igCacheEnabled: true, // Enable L2 IndexedDB cache (optional)
});

// List all imported IGs
const igs = await client.loadIGList();
// → IGSummary[] with id, url, version, name, status

// Load IG content index (profiles, extensions, valueSets, etc.)
const index = await client.loadIGIndex("us-core");
// → IGIndex with profiles[], extensions[], valueSets[], codeSystems[]

// Load a StructureDefinition with dependencies
const result = await client.loadIGStructure("us-core", "us-core-patient");
// → { sd: StructureDefinition, dependencies: ["http://..."] }

// Batch-load multiple resources (deduplicates cached ones)
const resources = await client.loadIGBundle("us-core", [
  "StructureDefinition/us-core-patient",
  "StructureDefinition/us-core-observation-lab",
]);

Cache Layers

| Layer | Storage | Lifetime | Invalidation | | ----- | ---------- | ------------- | -------------------------- | | L1 | Memory LRU | Session | Page refresh | | L2 | IndexedDB | Cross-session | IG version change | | L3 | Server | Permanent | ETag / If-None-Match → 304 |

API Reference

FhirClient

Main client class for interacting with FHIR servers.

Methods:

  • read<T>(type, id, options?) — Read a resource by ID
  • create<T>(type, resource, options?) — Create a new resource
  • update<T>(type, id, resource, options?) — Update a resource
  • patch(type, id, patch, options?) — Patch a resource with JSON Patch
  • delete(type, id, options?) — Delete a resource
  • search<T>(type, params?, options?) — Search resources
  • searchByUrl<T>(url, options?) — Search by full URL
  • history(type?, id?, params?, options?) — Get resource history
  • batch(bundle, options?) — Execute a batch/transaction Bundle
  • capabilities(options?) — Get server CapabilityStatement

SearchParamsBuilder

Fluent builder for constructing FHIR search parameters.

Methods:

  • where(param, value) — Add search parameter
  • sort(param, order?) — Add sort parameter
  • count(n) — Set page size
  • offset(n) — Set offset (for servers that support it)
  • include(resourceType, param) — Add _include
  • revInclude(resourceType, param) — Add _revinclude
  • summary(mode) — Set _summary mode
  • elements(...fields) — Set _elements
  • build() — Build final SearchParams object

TypeScript Support

Full TypeScript definitions included:

import type {
  Resource,
  Bundle,
  OperationOutcome,
  FhirClientOptions,
  SearchParams,
  RequestOptions,
} from "fhir-rest-client";

Browser Support

Works in all modern browsers with native fetch and crypto support:

  • Chrome/Edge 90+
  • Firefox 88+
  • Safari 14+

Node.js Support

Requires Node.js 18+ (native fetch and crypto.subtle support).

License

Apache-2.0

Contributing

Contributions welcome! Please see CONTRIBUTING.md for details.

Links