Skip to content

Commit 4abb003

Browse files
authored
Merge pull request #104 from mcode/fhir-validation-errors
Added fn to find all invalid resources in a bundle
2 parents cc13692 + b3aaff8 commit 4abb003

File tree

6 files changed

+75
-6
lines changed

6 files changed

+75
-6
lines changed

src/client/BaseClient.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { isValidFHIR } = require('../helpers/fhirUtils');
1+
const { isValidFHIR, invalidResourcesFromBundle } = require('../helpers/fhirUtils');
22
const logger = require('../helpers/logger');
33

44
class BaseClient {
@@ -97,7 +97,7 @@ class BaseClient {
9797
}, Promise.resolve(contextBundle));
9898

9999
if (!isValidFHIR(contextBundle)) {
100-
logger.error('Extracted bundle is not valid FHIR.');
100+
logger.warn(`Extracted bundle is not valid FHIR, the following resources failed validation: ${invalidResourcesFromBundle(contextBundle).join(',')}`);
101101
}
102102

103103
return { bundle: contextBundle, extractionErrors };

src/helpers/fhirUtils.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,22 @@ const logOperationOutcomeInfo = (operationOutcome) => {
163163
});
164164
};
165165

166-
const isValidFHIR = (resource) => validator.validate('FHIR', resource);
167-
166+
function isValidFHIR(resource) {
167+
return validator.validate('FHIR', resource);
168+
}
169+
function invalidResourcesFromBundle(bundle) {
170+
// Bundle is assumed to have all resources in bundle.entry[x].resource
171+
const failingResources = [];
172+
bundle.entry.forEach((e) => {
173+
const { resource } = e;
174+
const { id, resourceType } = resource;
175+
if (!validator.validate('FHIR', resource)) {
176+
const failureId = `${resourceType}-${id}`;
177+
failingResources.push(failureId);
178+
}
179+
});
180+
return failingResources;
181+
}
168182

169183
module.exports = {
170184
allResourcesInBundle,
@@ -182,4 +196,5 @@ module.exports = {
182196
mapFHIRVersions,
183197
quantityCodeToUnitLookup,
184198
isValidFHIR,
199+
invalidResourcesFromBundle,
185200
};

test/client/BaseClient.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ describe('BaseClient', () => {
7676
});
7777
it('should iterate over all extractors gets, aggregating resultant entries in a bundle', async () => {
7878
const extractorClassesWithEntryGets = [
79-
class Ext1 { get() { return { entry: [{ data: 'here' }] }; }},
80-
class Ext2 { get() { return { entry: [{ data: 'alsoHere' }] }; }},
79+
class Ext1 { get() { return { entry: [{ resource: 'here' }] }; }},
80+
class Ext2 { get() { return { entry: [{ resource: 'alsoHere' }] }; }},
8181
class Ext3 { get() { throw new Error('Error'); }},
8282
];
8383
engine.registerExtractors(...extractorClassesWithEntryGets);

test/helpers/fhirUtils.test.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@ const {
77
allResourcesInBundle,
88
quantityCodeToUnitLookup,
99
getResourceCountInBundle,
10+
isValidFHIR,
11+
invalidResourcesFromBundle,
1012
} = require('../../src/helpers/fhirUtils.js');
1113
const emptyBundle = require('./fixtures/emptyBundle.json');
1214
const bundleWithOneEntry = require('./fixtures/searchsetBundleWithOneEntry.json');
1315
const bundleWithMultipleEntries = require('./fixtures/searchsetBundleWithMultipleEntries.json');
1416
const countBundle5Unique = require('./fixtures/count-bundle-5-unique.json');
1517
const countBundle5Same = require('./fixtures/count-bundle-5-same.json');
1618
const countBundle5Nested = require('./fixtures/count-bundle-5-nested.json');
19+
const validResource = require('./fixtures/valid-resource');
20+
const invalidResource = require('./fixtures/invalid-resource');
1721

1822
describe('getQuantityUnit', () => {
1923
test('Should return unit text if provided in lookup table', () => {
@@ -137,3 +141,25 @@ describe('getResourceCountInBundle', () => {
137141
expect(getResourceCountInBundle(countBundle5Nested)).toEqual(counts);
138142
});
139143
});
144+
145+
describe('isValidFHIR', () => {
146+
test('Should return true when provided valid FHIR resources', () => {
147+
expect(isValidFHIR(validResource)).toEqual(true);
148+
});
149+
test('Should return false when provided invalid FHIR resources', () => {
150+
expect(isValidFHIR(invalidResource)).toEqual(false);
151+
});
152+
});
153+
154+
describe('invalidResourcesFromBundle', () => {
155+
test('Should return an empty array when all resources are valid', () => {
156+
expect(invalidResourcesFromBundle(emptyBundle)).toEqual([]);
157+
});
158+
test('Should return an array of all invalid resources when they exist', () => {
159+
const invalidBundle = { ...bundleWithOneEntry };
160+
invalidBundle.entry[0].resource = invalidResource;
161+
// This is dependent on implementation details intrinsic to invalidResourcesFromBundle
162+
const invalidResourceId = `${invalidResource.resourceType}-${invalidResource.id}`;
163+
expect(invalidResourcesFromBundle(invalidBundle)).toEqual([invalidResourceId]);
164+
});
165+
});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"resourceType": "Patient",
3+
"id": "invalid-patient",
4+
"name": [
5+
{
6+
"family": "Godel",
7+
"given": [
8+
"Kurt"
9+
]
10+
}
11+
],
12+
"gender": "invalid-enum-value",
13+
"birthDate": "1906-04-28"
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"resourceType": "Patient",
3+
"id": "valid-patient",
4+
"name": [
5+
{
6+
"family": "Frege",
7+
"given": [
8+
"Gottlob"
9+
]
10+
}
11+
],
12+
"gender": "male",
13+
"birthDate": "1848-11-08"
14+
}

0 commit comments

Comments
 (0)