Skip to main content

RESTful Requests

The fhir_r4_at_rest library provides a streamlined way to construct RESTful API calls for FHIR operations. Instead of dealing with the complexities of building URLs, handling HTTP methods, and managing headers, this library offers a type-safe approach through a collection of request classes.

Basic Concepts

All request classes in the library inherit from the abstract FhirRequest class, which provides common functionality:

  • Base URL management
  • HTTP headers configuration
  • URI construction
  • Response handling

Common Request Structure

All request classes share a similar construction pattern:

final request = FhirSomeRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'), // Base FHIR server URL
resourceType: 'Patient', // The FHIR resource type
id: '12345', // Resource ID (when applicable)
headers: {'Authorization': 'Bearer token123'}, // Custom HTTP headers
parameters: RestfulParameters() // Optional request parameters
.requestPretty()
.add('_count', '10'),
);

// Execute the request
final response = await request.sendRequest();

Request Types

The library supports all standard FHIR RESTful operations:

1. Read Request

Retrieves a specific resource by its ID.

final request = FhirReadRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
id: '12345',
headers: {'Authorization': 'Bearer token123'},
);

final response = await request.sendRequest();
// GET http://hapi.fhir.org/baseR4/Patient/12345?_format=json

2. VRead Request

Retrieves a specific version of a resource.

final request = FhirVReadRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
id: '12345',
vid: '2', // Version ID
headers: {'Authorization': 'Bearer token123'},
);

final response = await request.sendRequest();
// GET http://hapi.fhir.org/baseR4/Patient/12345/_history/2?_format=json

3. Update Request

Updates an existing resource.

final request = FhirUpdateRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
id: '12345',
resource: {
'resourceType': 'Patient',
'id': '12345',
'name': [
{
'given': ['John'],
'family': 'Doe',
},
],
},
headers: {'Authorization': 'Bearer token123'},
);

final response = await request.sendRequest();
// PUT http://hapi.fhir.org/baseR4/Patient/12345?_format=json

4. Patch Request

Applies a partial update to a resource using JSON Patch.

final patchBody = PatchBody()
..addOperation(
PatchOps.replace,
'/name/0/family',
value: 'Smith',
);

final request = FhirPatchRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
id: '12345',
patchBody: patchBody,
headers: {'Authorization': 'Bearer token123'},
);

final response = await request.sendRequest();
// PATCH http://hapi.fhir.org/baseR4/Patient/12345?_format=json

5. Delete Request

Deletes a resource by its ID.

final request = FhirDeleteRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
id: '12345',
headers: {'Authorization': 'Bearer token123'},
);

final response = await request.sendRequest();
// DELETE http://hapi.fhir.org/baseR4/Patient/12345?_format=json

6. Create Request

Creates a new resource.

final request = FhirCreateRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
resource: {
'resourceType': 'Patient',
'name': [
{
'given': ['John'],
'family': 'Doe',
},
],
},
headers: {'Authorization': 'Bearer token123'},
);

final response = await request.sendRequest();
// POST http://hapi.fhir.org/baseR4/Patient?_format=json

7. History Request

Retrieves the history of changes to a specific resource.

final request = FhirHistoryRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
id: '12345',
headers: {'Authorization': 'Bearer token123'},
);

final response = await request.sendRequest();
// GET http://hapi.fhir.org/baseR4/Patient/12345/_history?_format=json

8. History All Request

Retrieves the history of changes to all resources.

final request = FhirHistoryAllRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
headers: {'Authorization': 'Bearer token123'},
);

final response = await request.sendRequest();
// GET http://hapi.fhir.org/baseR4/_history?_format=json

9. Capabilities Request

Retrieves the server's capability statement.

final request = FhirCapabilitiesRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
mode: Mode.normative, // Optional: full, normative, or terminology
headers: {'Authorization': 'Bearer token123'},
);

final response = await request.sendRequest();
// GET http://hapi.fhir.org/baseR4/metadata?mode=normative&_format=json

10. Transaction Request

Submits a bundle of operations to be processed as a single transaction.

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(),
headers: {'Authorization': 'Bearer token123'},
);

final response = await request.sendRequest();
// POST http://hapi.fhir.org/baseR4?_format=json

11. Batch Request

Similar to Transaction but allows operations to be processed independently.

final bundle = Bundle(
type: BundleType.batch,
entry: [
BundleEntry(
request: BundleRequest(
method: HTTPVerb.GET,
url: FhirUri('Patient/12345'),
),
),
BundleEntry(
request: BundleRequest(
method: HTTPVerb.POST,
url: FhirUri('Observation'),
),
resource: Observation(
status: ObservationStatus.final_,
code: CodeableConcept(
coding: [
Coding(
system: FhirUri('http://loinc.org'),
code: FhirCode('12345-6'),
),
],
),
),
),
],
);

final request = FhirBatchRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
bundle: bundle.toJson(),
headers: {'Authorization': 'Bearer token123'},
);

final response = await request.sendRequest();
// POST http://hapi.fhir.org/baseR4?_format=json

12. Operation Request

Invokes a named operation on the server, resource type, or resource instance.

// Server-level operation
final request = FhirOperationRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
operation: 'everything',
parameters: RestfulParameters()
.add('start', '2020-01-01')
.add('end', '2020-12-31'),
headers: {'Authorization': 'Bearer token123'},
);

// Resource type operation
final typeRequest = FhirOperationRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
operation: 'everything',
headers: {'Authorization': 'Bearer token123'},
);

// Resource instance operation
final instanceRequest = FhirOperationRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
id: '12345',
operation: 'everything',
headers: {'Authorization': 'Bearer token123'},
);

final response = await request.sendRequest();
// GET http://hapi.fhir.org/baseR4/$everything?start=2020-01-01&end=2020-12-31&_format=json
// GET http://hapi.fhir.org/baseR4/Patient/$everything?_format=json
// GET http://hapi.fhir.org/baseR4/Patient/12345/$everything?_format=json

Request Parameters

All request classes support optional parameters through the RestfulParameters class:

final parameters = RestfulParameters()
.requestPretty() // Pretty-print the response
.requestSummary(Summary.true_) // Request summary data only
.add('_count', '10') // Limit results to 10 items
.add('_since', '2020-01-01'); // Only include resources modified after this date

final request = FhirReadRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
id: '12345',
parameters: parameters,
);

Working with HTTP Client

By default, the library uses http.Client() to make requests. You can provide your own client for custom behavior:

final customClient = http.Client();

final request = FhirReadRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
id: '12345',
client: customClient,
);

Handling Responses

The sendRequest() method returns a standard http.Response object:

final request = FhirReadRequest(
base: Uri.parse('http://hapi.fhir.org/baseR4'),
resourceType: 'Patient',
id: '12345',
);

try {
final response = await request.sendRequest();

if (response.statusCode == 200) {
// Parse the response body
final patient = Patient.fromJson(
jsonDecode(response.body),
);
// Use the patient resource
} else {
// Handle error responses
print('Error: ${response.statusCode} - ${response.body}');
}
} catch (e) {
// Handle network or other exceptions
print('Exception: $e');
}

Conclusion

The fhir_r4_at_rest library simplifies interactions with FHIR servers by providing typed classes for each RESTful operation. This approach improves code readability and reduces the likelihood of errors when constructing FHIR API requests.