This document describes how MediLink implements the HL7 FHIR R4 specification — which resource types are supported, what search parameters are available, and how data is stored and returned.
- Overview
- Supported Resources
- Resource Storage Model
- Search Parameters by Resource
- FHIR Bundle Responses
- Resource Versioning & History
- Custom Operations
- Validation Rules
- Content Types
- Reference Validation
MediLink implements a subset of FHIR R4 focused on the clinical resources needed for a healthcare coordination platform. All resources are stored as JSONB in PostgreSQL with server-assigned IDs and metadata.
What MediLink implements:
- 10 clinical resource types
- CRUD operations (create, read, update, delete) for all resources
- Search with FHIR-standard query parameters
- Resource versioning and history
- FHIR Bundle responses for search and history
- Two custom operations (
$timelineand$lab-trends) - Cross-resource reference validation
What MediLink does not implement:
- FHIR XML format (JSON only)
- Capability statement / conformance endpoint
- Subscriptions
- Batch/Transaction bundles
- Contained resources
- Extensions beyond standard fields
| Resource | Description | Patient-Scoped |
|---|---|---|
| Patient | Demographics, identifiers, contact information | Self |
| Practitioner | Healthcare provider information | No |
| Organization | Healthcare organizations | No |
| Encounter | Clinical visits and admissions | Yes |
| Condition | Diagnoses and health conditions | Yes |
| MedicationRequest | Prescriptions and medication orders | Yes |
| Observation | Lab results, vitals, clinical findings | Yes |
| DiagnosticReport | Lab reports and diagnostic studies | Yes |
| AllergyIntolerance | Allergies and adverse reactions | Yes |
| Immunization | Vaccination records | Yes |
Patient-Scoped means the resource is linked to a specific patient via a patient_ref column. Consent-based access control is enforced for these resources.
All FHIR resources are stored in a single PostgreSQL table:
CREATE TABLE fhir_resources (
id UUID PRIMARY KEY,
fhir_id TEXT UNIQUE NOT NULL,
resource_type TEXT NOT NULL,
data JSONB NOT NULL,
patient_ref TEXT,
version INTEGER DEFAULT 1,
created_at TIMESTAMPTZ,
updated_at TIMESTAMPTZ,
deleted_at TIMESTAMPTZ
);Key design decisions:
fhir_idis the logical ID used in FHIR references (e.g.,Patient/abc-123)datastores the full FHIR JSON resourcepatient_refstores the patient FHIR ID for consent scoping (format:Patient/abc-123)versionis incremented on each updatedeleted_atenables soft delete (resource is marked deleted, not removed)- Patients are stored in a separate
patientstable with additional PII encryption
All search endpoints support pagination via _count (default: 20, max: 100) and _offset (default: 0).
| Parameter | Type | Description |
|---|---|---|
family |
string | Family (last) name |
given |
string | Given (first) name |
name |
string | Any part of the name (family, given, text) |
birthdate |
date | Date of birth |
gender |
token | male, female, other, unknown |
identifier |
token | Identifier value (e.g., MRN) |
active |
boolean | Whether the patient record is active |
| Parameter | Type | Description |
|---|---|---|
family |
string | Family name |
given |
string | Given name |
name |
string | Any part of the name |
identifier |
token | Identifier value (e.g., NPI) |
gender |
token | Gender |
active |
boolean | Active status |
| Parameter | Type | Description |
|---|---|---|
name |
string | Organization name (partial match) |
identifier |
token | Identifier value |
type |
token | Organization type code |
active |
boolean | Active status |
| Parameter | Type | Description |
|---|---|---|
patient |
reference | Patient FHIR ID |
status |
token | planned, arrived, in-progress, finished, etc. |
class |
token | AMB, IMP, EMER, etc. |
date |
date | Encounter start date (supports prefixes) |
practitioner |
reference | Practitioner reference |
organization |
reference | Service provider reference |
| Parameter | Type | Description |
|---|---|---|
patient |
reference | Patient FHIR ID |
clinical-status |
token | active, recurrence, relapse, inactive, remission, resolved |
verification-status |
token | unconfirmed, provisional, differential, confirmed |
code |
token | Condition code (e.g., ICD-10 or SNOMED CT code) |
onset-date |
date | Onset date (supports prefixes) |
encounter |
reference | Encounter reference |
| Parameter | Type | Description |
|---|---|---|
patient |
reference | Patient FHIR ID |
status |
token | active, on-hold, cancelled, completed, stopped, draft, entered-in-error, unknown |
medication |
token | Medication code |
intent |
token | proposal, plan, order, original-order, reflex-order, filler-order, instance-order, option |
encounter |
reference | Encounter reference |
authored-on |
date | Authored date (supports prefixes) |
requester |
reference | Prescribing practitioner reference |
| Parameter | Type | Description |
|---|---|---|
patient |
reference | Patient FHIR ID |
code |
token | Observation code (e.g., LOINC code) |
category |
token | Category code (e.g., laboratory, vital-signs) |
status |
token | registered, preliminary, final, amended |
date |
date | Effective date (supports prefixes) |
encounter |
reference | Encounter reference |
value-quantity |
quantity | Numeric value comparison (supports prefixes) |
| Parameter | Type | Description |
|---|---|---|
patient |
reference | Patient FHIR ID |
status |
token | registered, partial, preliminary, final |
category |
token | Category code |
code |
token | Report code |
date |
date | Effective date (supports prefixes) |
encounter |
reference | Encounter reference |
| Parameter | Type | Description |
|---|---|---|
patient |
reference | Patient FHIR ID |
clinical-status |
token | active, inactive, resolved |
criticality |
token | low, high, unable-to-assess |
code |
token | Allergy/substance code |
category |
token | food, medication, environment, biologic |
| Parameter | Type | Description |
|---|---|---|
patient |
reference | Patient FHIR ID |
status |
token | completed, entered-in-error, not-done |
vaccine-code |
token | Vaccine code (e.g., CVX code) |
date |
date | Occurrence date (supports prefixes) |
Date parameters support comparison prefixes:
| Prefix | Meaning | Example |
|---|---|---|
eq |
Equal (default) | date=eq2024-01-15 |
gt |
Greater than | date=gt2024-01-01 |
lt |
Less than | date=lt2024-12-31 |
ge |
Greater or equal | date=ge2024-06-01 |
le |
Less or equal | date=le2024-06-30 |
Search and history endpoints return FHIR Bundle resources:
{
"resourceType": "Bundle",
"type": "searchset",
"total": 42,
"link": [
{
"relation": "self",
"url": "https://medilink.dev/fhir/Observation?patient=Patient/abc-123&_count=20&_offset=0"
},
{
"relation": "next",
"url": "https://medilink.dev/fhir/Observation?patient=Patient/abc-123&_count=20&_offset=20"
}
],
"entry": [
{
"fullUrl": "https://medilink.dev/fhir/Observation/obs-uuid-1",
"resource": {
"resourceType": "Observation",
"id": "obs-uuid-1",
"status": "final",
"code": { ... },
"subject": { "reference": "Patient/abc-123" },
"effectiveDateTime": "2024-03-15T10:30:00Z",
"valueQuantity": { "value": 120, "unit": "mg/dL" }
}
}
]
}History bundles use "type": "history" and include a request object in each entry showing the HTTP method.
Every FHIR resource has a version number that starts at 1 and increments on each update.
GET /fhir/Observation/obs-uuid-1/_history/3
Returns version 3 of the Observation.
GET /fhir/Observation/obs-uuid-1/_history
Returns a Bundle containing all versions, most recent first.
The meta field on each resource includes:
{
"meta": {
"versionId": "3",
"lastUpdated": "2024-03-15T10:30:00Z"
}
}GET /fhir/Patient/{fhirId}/$timeline?_count=50&_offset=0
Returns a chronological Bundle of all clinical resources linked to a patient, sorted by date (most recent first). This includes Encounters, Conditions, Observations, MedicationRequests, DiagnosticReports, AllergyIntolerances, and Immunizations.
Useful for displaying a patient's complete health timeline in the dashboard.
GET /fhir/Observation/$lab-trends?patient={patientFhirId}&code={loincCode}
Returns all Observations for a patient with a specific LOINC code, sorted chronologically. Used to graph trends for a specific lab test over time (e.g., blood glucose readings across months).
Every resource is validated before storage. Common validation rules:
resourceTypemust match the endpoint (e.g.,POST /fhir/PatientrequiresresourceType: "Patient")- If
idis provided in the body, it must match the URL parameter (for updates) - All referenced resources must exist and be active (see Reference Validation)
namearray with at least one entry containingfamilyname is requiredgenderis required and must be one of:male,female,other,unknownbirthDatemust be a valid date inYYYY-MM-DDformat if provided
namearray with at least one entry containingfamilyname is requiredgendermust be valid if provided
nameis required
statusis required (valid:planned,arrived,triaged,in-progress,onleave,finished,cancelled,entered-in-error,unknown)classcoding is required withsystemandcodesubjectreference to a Patient is requiredperiod.startmust be beforeperiod.endif both are provided
subjectreference to a Patient is requiredcodewith at least one coding is requiredclinicalStatusis required with valid value
statusis requiredintentis requiredsubjectreference to a Patient is requiredmedicationCodeableConceptwith at least one coding is required- Drug interaction check is performed automatically — contraindicated interactions block creation
statusis requiredcodewith at least one coding is requiredsubjectreference to a Patient is required
statusis requiredcodewith at least one coding is required
patientreference is requiredcodewith at least one coding is required
statusis requiredvaccineCodewith at least one coding is requiredpatientreference is requiredoccurrenceDateTimeis required
| Header | Value |
|---|---|
Request Content-Type |
application/json or application/fhir+json |
Response Content-Type |
application/fhir+json; charset=utf-8 |
All responses use FHIR JSON format. XML is not supported.
When a resource references another resource (e.g., an Observation referencing a Patient), MediLink validates that:
- The referenced resource exists in the database
- The referenced resource is not deleted
- The resource type matches the expected type (e.g., a
subjectreference must point to a Patient)
Invalid references return a 422 Unprocessable Entity error with a FHIR OperationOutcome:
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "processing",
"diagnostics": "Referenced resource Patient/nonexistent-id not found"
}
]
}References use the format ResourceType/fhir-id (e.g., Patient/abc-123, Practitioner/dr-456).