fhir_r4_at_rest
A Dart package for building FHIR R4 RESTful requests and parsing responses. This package handles request construction and response parsing, while authentication is handled by passing authenticated HTTP clients (e.g., from the fhir_r4_auth package).
FHIR® is the registered trademark of HL7 and is used with the permission of HL7. Use of the FHIR trademark does not constitute endorsement of this product by HL7.
Features
- Type-safe request builders for all FHIR RESTful operations
- Fluent interface for constructing complex queries
- Resource-specific search parameter builders
- Structured response parsing with
ReturnResults - Works with any HTTP client (authenticated or not)
- Comprehensive parameter validation
Quick Start
import 'package:fhir_r4_at_rest/fhir_r4_at_rest.dart';
import 'package:fhir_r4/fhir_r4.dart';
// Simple read from an open server
final request = FhirReadRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
id: '12345',
);
final response = await request.sendRequest();
final patient = Patient.fromJson(jsonDecode(response.body));
Installation
dependencies:
fhir_r4_at_rest: ^0.4.0
fhir_r4: ^0.4.2
# Optional: For authenticated requests
fhir_r4_auth: ^0.4.0
FHIR Version Support
This package supports FHIR R4. For other FHIR versions, see:
fhir_r5_at_rest- R5 supportfhir_r6_at_rest- R6 support
Basic Usage
Reading a Resource
final request = FhirReadRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
id: '12345',
headers: {'Authorization': 'Bearer token123'},
);
final response = await request.sendRequest();
Creating a Resource
final patient = Patient(
name: [
HumanName(
family: 'Doe'.toFhirString,
given: ['John'.toFhirString],
),
],
);
final request = FhirCreateRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
resource: patient.toJson(),
headers: {'Authorization': 'Bearer token123'},
);
final response = await request.sendRequest();
Updating a Resource
final patient = Patient(
id: '12345'.toFhirString,
name: [
HumanName(
family: 'Doe'.toFhirString,
given: ['John'.toFhirString],
),
],
);
final request = FhirUpdateRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
id: '12345',
resource: patient.toJson(),
headers: {'Authorization': 'Bearer token123'},
);
final response = await request.sendRequest();
Deleting a Resource
final request = FhirDeleteRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
id: '12345',
headers: {'Authorization': 'Bearer token123'},
);
final response = await request.sendRequest();
Request Parameters
The library provides a fluent API for building request parameters:
final parameters = RestfulParameters()
.requestPretty()
.addCount(10)
.requestSummary(Summary.true_)
.add('_format', 'json');
final request = FhirReadRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
id: '12345',
parameters: parameters,
);
Type-Safe Searching
The library provides type-safe search builders for FHIR resources:
// Search for active male patients born after 1970
final search = SearchPatient()
.active(FhirString('true'))
.gender(FhirString('male'))
.birthdate(
FhirDateTime('1970-01-01'),
modifier: SearchModifier.gt,
);
final request = FhirSearchRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
search: search,
);
final response = await request.sendRequest();
Advanced Operations
Working with History
final request = FhirHistoryRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
id: '12345',
parameters: RestfulParameters()
.add('_count', '10')
.add('_since', '2020-01-01'),
);
final response = await request.sendRequest();
Batch and Transaction Operations
final bundle = Bundle(
type: BundleType.transaction,
entry: [
BundleEntry(
request: BundleRequest(
method: HTTPVerb.POST,
url: FhirUri('Patient'),
),
resource: Patient(
name: [
HumanName(
family: FhirString('Doe'),
given: [FhirString('John')],
),
],
),
),
],
);
final request = FhirTransactionRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
bundle: bundle.toJson(),
);
final response = await request.sendRequest();
Capabilities Statement
final request = FhirCapabilitiesRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
mode: Mode.normative,
);
final response = await request.sendRequest();
Custom Operations
final request = FhirOperationRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
id: '12345',
operation: 'everything',
parameters: RestfulParameters()
.add('start', '2020-01-01')
.add('end', '2020-12-31'),
);
final response = await request.sendRequest();
Handling Responses
Basic Response Handling
try {
final response = await request.sendRequest();
if (response.statusCode == 200) {
final patient = Patient.fromJson(
jsonDecode(response.body),
);
// Work with the patient resource
} else {
// Handle error response
print('Error: ${response.statusCode}');
print('Body: ${response.body}');
}
} catch (e) {
// Handle network or parsing exceptions
print('Exception: $e');
}
Using ReturnResults for Structured Response Handling
The library provides ReturnResults to separate successful resources from errors:
final response = await request.sendRequest();
final resource = Resource.fromJson(jsonDecode(response.body));
final result = parseRequestResult(resource);
// Check for successfully returned resources
if (result.resources.isNotEmpty) {
for (final resource in result.resources) {
// Process each resource
print('Retrieved resource: ${resource.id}');
}
}
// Check for error OperationOutcomes
if (result.errorOperationOutcomes.isNotEmpty) {
for (final error in result.errorOperationOutcomes) {
print('Error: ${error.issue.first.diagnostics}');
}
}
// Check for informational OperationOutcomes
if (result.informationOperationOutcomes.isNotEmpty) {
for (final info in result.informationOperationOutcomes) {
print('Info: ${info.issue.first.diagnostics}');
}
}
Custom HTTP Client
final client = http.Client(); // Your custom HTTP client
final request = FhirReadRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
id: '12345',
client: client,
);
Authentication
This package works with any HTTP client, including authenticated clients from the fhir_r4_auth package.
Using with fhir_r4_auth Package
import 'package:fhir_r4_auth/fhir_r4_auth.dart';
// Create and authenticate a SMART on FHIR client
final authClient = SmartFhirClient(
fhirUri: FhirUri('https://server.org/fhir'),
clientId: 'my-client-id',
redirectUri: FhirUri('https://myapp.com/callback'),
scopes: ['patient/*.read'],
);
await authClient.login();
// Pass the authenticated client to any request
final request = FhirReadRequest(
base: Uri.parse('https://server.org/fhir'),
resourceType: 'Patient',
id: '12345',
client: authClient, // Authenticated client handles auth headers
);
final response = await request.sendRequest();
Using with Custom Headers
For simple token-based authentication without a full OAuth flow:
final request = FhirReadRequest(
base: Uri.parse('https://server.org/fhir'),
resourceType: 'Patient',
id: '12345',
headers: {'Authorization': 'Bearer your-access-token'},
);
Using with Any Custom HTTP Client
// Any client that extends http.Client
final customClient = MyCustomHttpClient();
final request = FhirReadRequest(
base: Uri.parse('https://server.org/fhir'),
resourceType: 'Patient',
id: '12345',
client: customClient,
);
Documentation
For more detailed documentation, examples, and API reference, visit: FHIR-FLI Documentation
License
This project is licensed under the MIT License - see the LICENSE file for details.
FHIR® is the registered trademark of Health Level Seven International (HL7) and its use does not constitute endorsement of products by HL7®.