
Exposing a FHIR RESTful API to external consumers isn't just "turn on endpoints." Five design patterns cover most production challenges around auth, rate limits, versioning, and versioning strategy.
Pattern 1: Auth server separated from resource server. SMART on FHIR mandates OAuth 2.0 with a distinct authorization server. Keycloak, Auth0, or purpose-built work. The resource server enforces scopes handed down in the access token.
Pattern 2: Rate limits per token, per scope. Aggressive per-app rate limits protect the FHIR store. SMART v2 scopes (patient/Observation.rs) support fine-grained limits: read-heavy apps get higher read allocation than write-heavy apps.
Pattern 3: Version negotiation. Accept header (Accept: application/fhir+json; fhirVersion=4.0) selects R4 vs R5. Most 2026 deployments serve R4 by default but expose R5 for early adopters.
Pattern 4: CORS for browser clients. SMART patient apps launched from EHR portals need CORS headers. Whitelist EHR launch domains explicitly.
Pattern 5: Idempotency keys for POST. Bundle transaction POSTs should carry idempotency keys (a UUID header). The FHIR REST spec covers If-None-Exist for basic conditional creates.
Common design mistakes
| Mistake | Impact |
|---|---|
| Single global rate limit | Aggressive apps drown low-volume ones |
| No version negotiation | R4/R5 forks in the codebase |
| Missing CORS | SMART apps silently fail |
| No idempotency | Retry storms create duplicates |
| Auth in resource server | Wrong security model |
FHIR RESTful APIs are well-specified; the design patterns above are what make the difference between a demo and production.