Skip to content
fhir-api logo

fhir-api

Expert guidance for implementing FHIR RESTful API servers and clients following the HL7 FHIR specification. Use this skill when implementing a FHIR server with REST endpoints, building a FHIR client, designing FHIR API routes and handlers, implementing FHIR operations (read, create, update, delet...

aehrc/pathling0installs137stars

SKILL.md

Full skill instructions

FHIR REST API implementation

This skill provides guidance for implementing FHIR RESTful APIs according to the HL7 FHIR specification (R4/​R5).

URL structure

All FHIR REST URLs follow the pattern:

[base]/[type]/[id]
  • [base]: Service base URL (e.g., https://fhir.example.org/r4)
  • [type]: Resource type (e.g., Patient, Observation)
  • [id]: Logical resource ID

URLs are case-sensitive and use UTF-8 encoding.

Core operations

OperationHTTPURL PatternSuccess
ReadGET[base]/[type]/[id]200
VReadGET[base]/[type]/[id]/​_history/[vid]200
CreatePOST[base]/[type]201
UpdatePUT[base]/[type]/[id]200/​201
PatchPATCH[base]/[type]/[id]200
DeleteDELETE[base]/[type]/[id]200/​204
SearchGET/​POST[base]/[type]?params200
HistoryGET[base]/[type]/[id]/​_history200
CapabilitiesGET[base]/​metadata200
Batch/​TransactionPOST[base]200

For detailed specifications of each operation, see references/​operations.md.

Content negotiation

MIME types

FormatMIME Type
JSONapplication/​fhir+json
XMLapplication/​fhir+xml
RDFapplication/​fhir+turtle

Use the Accept header for response format and Content-Type for request body format.

The _format query parameter overrides Accept when clients cannot set headers.

FHIR version

Specify version via MIME type parameter:

Accept: application/​fhir+json; fhirVersion=4.0

Version mappings: 1.0 (R2), 3.0 (R3), 4.0 (R4), 4.3 (R4B), 5.0 (R5).

Required headers

Request headers

HeaderPurposeExample
AcceptResponse formatapplication/​fhir+json
Content-TypeRequest body formatapplication/​fhir+json
If-MatchOptimistic lockingW/"123"
If-None-ExistConditional createidentifier=123
PreferReturn preferencereturn=representation

Response headers

HeaderPurposeExample
ETagVersion identifierW/"123"
LocationNew resource URL[base]/​Patient/​123/​_history/​1
Last-ModifiedModification timeRFC 7231 date

Versioning and optimistic locking

FHIR uses weak ETags for version tracking:

  1. Server returns ETag: W/"[versionId]" with responses
  2. Client sends If-Match: W/"[versionId]" with updates
  3. Server returns 412 Precondition Failed if version mismatch

Implement version-aware updates when CapabilityStatement.rest.resource.versioning is versioned-update.

Error handling

Return OperationOutcome resources for all errors:

{
    "resourceType": "OperationOutcome",
    "issue": [
        {
            "severity": "error",
            "code": "invalid",
            "diagnostics": "Patient.birthDate: Invalid date format"
        }
    ]
}

Status codes

CodeMeaning
400Invalid syntax or validation failure
404Resource not found
409Version conflict
410Resource deleted
412Precondition failed (version mismatch)
422Business rule violation

Prefer header

Control response content with Prefer:

ValueResponse body
return=minimalEmpty (headers only)
return=representationFull resource
return=OperationOutcomeValidation outcome

For async operations, use Prefer: respond-async to get 202 Accepted with status polling URL.

Implementation checklist

Server implementations should:

  1. Implement CapabilityStatement at /​metadata
  2. Support content negotiation (JSON at minimum)
  3. Return proper ETags for versioned resources
  4. Include Location header on create/​update
  5. Return OperationOutcome for all errors
  6. Support _format parameter fallback
  7. Honour Prefer header for response content

References