fhir_r4_bulk 0.3.0 copy "fhir_r4_bulk: ^0.3.0" to clipboard
fhir_r4_bulk: ^0.3.0 copied to clipboard

Library to support the FHIR Bulk Data Access API (https://www.hl7.org/fhir/uv/bulkdata/index.html) for FHIR R4 resources.

example/main.dart

// ignore_for_file: avoid_print

import 'dart:convert';
import 'package:fhir_r4/fhir_r4.dart';
import 'package:fhir_r4_bulk/fhir_r4_bulk.dart';
import 'package:http/http.dart' as http;
import 'package:http/testing.dart';
import 'package:test/test.dart';

void main() {
  group('Unit Tests for Bulk Export (Mock)', () {
    test('GET-based export handles 202 + polling to 200 + NDJSON download',
        () async {
      // 1) We'll simulate a 202 response with content-location
      //    Then a 200 response with final output
      //    Then NDJSON download
      var callCount = 0;
      final mockClient = MockClient((request) async {
        callCount++;
        if (callCount == 1) {
          // Kick-off -> 202
          return http.Response(
            '',
            202,
            headers: {
              'content-location': 'http://fake-server/poll',
            },
          );
        } else if (callCount == 2) {
          // Poll -> 200 final
          final bodyJson = jsonEncode(
            {
              'transactionTime': '2023-01-01T00:00:00Z',
              'output': [
                {
                  'type': 'Patient',
                  'url': 'http://fake-server/exported/patients.ndjson',
                },
              ],
            },
          );
          return http.Response(bodyJson, 200);
        } else if (callCount == 3) {
          // NDJSON download
          const ndjson = '''
{"resourceType":"Patient","id":"123"}
{"resourceType":"Patient","id":"456"}
''';
          return http.Response(
            ndjson,
            200,
            headers: {
              'content-type': 'application/fhir+ndjson',
            },
          );
        }
        return http.Response('Unexpected', 400);
      });

      final req = BulkRequestPatient(
        base: Uri.parse('http://fake-server/fhir'),
        client: mockClient,
      );

      final result = await req.request();
      expect(result, hasLength(2));
      expect(result.first, isA<Patient>());
      expect((result.first! as Patient).id, FhirString('123'));
    });

    test('POST-based export handles 202 + polling', () async {
      var callCount = 0;
      final mockClient = MockClient((request) async {
        callCount++;
        if (callCount == 1) {
          // Kick-off -> 202
          return http.Response(
            '',
            202,
            headers: {
              'content-location': 'http://fake-server/poll',
            },
          );
        } else if (callCount == 2) {
          // Poll -> 200 final
          final bodyJson = jsonEncode(
            {
              'transactionTime': '2023-02-02T00:00:00Z',
              'output': [
                {
                  'type': 'Patient',
                  'url': 'http://fake-server/export/patients.ndjson',
                },
              ],
            },
          );
          return http.Response(bodyJson, 200);
        } else if (callCount == 3) {
          // NDJSON
          const ndjson = '''
{"resourceType":"Patient","id":"abc"}
''';
          return http.Response(
            ndjson,
            200,
            headers: {
              'content-type': 'application/fhir+ndjson',
            },
          );
        }
        return http.Response('Unexpected', 400);
      });

      final req = BulkRequestGroup(
        base: Uri.parse('http://fake-server/fhir'),
        id: FhirId('MyGroup'),
        client: mockClient,
        useHttpPost: true, // <--- we do POST-based approach
        types: [
          WhichResource(R4ResourceType.Patient),
        ],
      );

      final result = await req.request();
      expect(result, hasLength(1));
      expect(result.first, isA<Patient>());
      expect((result.first! as Patient).id, FhirString('abc'));
    });
  });

  group('Unit Tests for Bulk Import (Mock)', () {
    test('Import returns OperationOutcome with job ID', () async {
      final mockClient = MockClient((request) async {
        final outcome = {
          'resourceType': 'OperationOutcome',
          'issue': [
            {
              'severity': 'information',
              'code': 'informational',
              'diagnostics': 'Bulk import job started with ID: 1234',
            },
          ],
        };
        return http.Response(jsonEncode(outcome), 202);
      });

      final req = BulkImportRequest(
        base: Uri.parse('http://fake-server/fhir'),
        files: [
          ImportFile(
            resourceType: R4ResourceType.Patient,
            url: Uri.parse('http://fake/patients.ndjson'),
          ),
        ],
        client: mockClient,
      );

      final outcome = await req.importData();
      expect(outcome.issue, isNotEmpty);
      expect(
        outcome.issue.first.diagnostics?.valueString,
        contains('ID: 1234'),
      );
    });
  });

  group('Integration Test Example (REAL)', () {
    // This is just a template. Adjust the URLs and any needed auth tokens
    // for whichever server you want to test (e.g. SMART Bulk Data sandbox).
    //
    // Because the public SMART sandbox might require ephemeral JWKS for auth,
    // you can skip if you have no token or do open endpoints. Or you might try
    // a local HAPI instance where you enabled $export.

    test(
        'Real-world POST-based Group Export (point to a real Bulk Data server)',
        () async {
      // For example, the ephemeral SMART Bulk Data server URL:
      final baseUrl = Uri.parse(
        'https://bulk-data.smarthealthit.org/eyJlcnIiOiIiLCJwYWdlIjoxMDAwMCwidGx0IjoxNSwibSI6MSwiZGVsIjowLCJzZWN1cmUiOjB9/fhir',
      );

      // If the server needs auth (JWT), you'd get a token here, e.g.:
      // final token = await getSmartBulkDataToken(...);
      // final headers = {
      //   'Authorization': 'Bearer $token',
      //   'content-type': 'application/fhir+json',
      // };
      // If no auth needed, do minimal headers:
      final headers = {
        'content-type': 'application/fhir+json',
        'accept': 'application/fhir+json',
      };

      final req = BulkRequestGroup(
        base: baseUrl,
        id: FhirId('HarvardPilgrimHealthCare'),
        headers: headers,
        useHttpPost: true, // do POST
        // Optionally specify resource types
        types: [
          WhichResource(R4ResourceType.AllergyIntolerance),
          WhichResource(R4ResourceType.Device),
          WhichResource(R4ResourceType.ImagingStudy),
          WhichResource(R4ResourceType.Patient),
          WhichResource(R4ResourceType.DocumentReference),
          WhichResource(R4ResourceType.Immunization),
        ],
      );

      final resources = await req.request();
      print('Got ${resources.length} resources from real server '
          '(or OperationOutcome).');
      for (final r in resources) {
        if (r is OperationOutcome) {
          print('OperationOutcome: ${r.issue.first.diagnostics?.valueString}');
        } else {
          print(
            'Resource: ${r?.resourceType}, id=${(r as DomainResource?)?.id}',
          );
        }
      }

      // Just check that it's a list of Resource?
      //(including possibly OperationOutcomes)
      expect(resources, isA<List<Resource?>>());
    });
  });
}
0
likes
160
points
236
downloads

Publisher

verified publisherfhirfli.dev

Weekly Downloads

Library to support the FHIR Bulk Data Access API (https://www.hl7.org/fhir/uv/bulkdata/index.html) for FHIR R4 resources.

Homepage
Repository (GitHub)

Documentation

API reference

License

MIT (license)

Dependencies

archive, fhir_r4, http, mime, universal_io

More

Packages that depend on fhir_r4_bulk