in src/router/bundle/bundleHandler.ts [108:207]
async processTransaction(
bundleRequestJson: any,
userIdentity: KeyValueMap,
requestContext: RequestContext,
serverUrl: string,
tenantId?: string,
) {
const startTime = new Date();
await validateResource(this.validators, bundleRequestJson);
let requests: BatchReadWriteRequest[];
try {
// TODO use the correct persistence layer
const resourcesServerDoesNotSupport = this.resourcesInBundleThatServerDoesNotSupport(bundleRequestJson);
if (resourcesServerDoesNotSupport.length > 0) {
let message = '';
resourcesServerDoesNotSupport.forEach(({ resource, operations }) => {
message += `${resource}: ${operations},`;
});
message = message.substring(0, message.length - 1);
throw new Error(`Server does not support these resource and operations: {${message}}`);
}
if (this.genericResource) {
requests = await BundleParser.parseResource(
bundleRequestJson,
this.genericResource.persistence,
this.serverUrl,
);
} else {
throw new Error('Cannot process bundle');
}
} catch (e) {
throw new createError.BadRequest((e as any).message);
}
await this.authService.isBundleRequestAuthorized({
userIdentity,
requestContext,
requests,
fhirServiceBaseUrl: serverUrl,
});
if (requests.length > MAX_BUNDLE_ENTRIES) {
throw new createError.BadRequest(
`Maximum number of entries for a Bundle is ${MAX_BUNDLE_ENTRIES}. There are currently ${requests.length} entries in this Bundle`,
);
}
const bundleServiceResponse = await this.bundleService.transaction({ requests, startTime, tenantId });
if (!bundleServiceResponse.success) {
if (bundleServiceResponse.errorType === 'SYSTEM_ERROR') {
throw new createError.InternalServerError(bundleServiceResponse.message);
} else if (bundleServiceResponse.errorType === 'USER_ERROR') {
throw new createError.BadRequest(bundleServiceResponse.message);
} else if (bundleServiceResponse.errorType === 'CONFLICT_ERROR') {
throw new createError.Conflict(bundleServiceResponse.message);
}
}
const readOperations = [
'read',
'vread',
'history-type',
'history-instance',
'history-system',
'search-type',
'search-system',
];
const authAndFilterReadPromises = requests.map((request, index) => {
if (readOperations.includes(request.operation)) {
return this.authService.authorizeAndFilterReadResponse({
operation: request.operation,
userIdentity,
requestContext,
readResponse: bundleServiceResponse.batchReadWriteResponses[index].resource,
fhirServiceBaseUrl: serverUrl,
});
}
return Promise.resolve();
});
const readResponses = await Promise.allSettled(authAndFilterReadPromises);
requests.forEach((request, index) => {
const entryResponse = bundleServiceResponse.batchReadWriteResponses[index];
if (readOperations.includes(request.operation)) {
const readResponse: { status: string; reason?: any; value?: any } = readResponses[index];
if (readResponse.reason && isUnauthorizedError(readResponse.reason)) {
entryResponse.resource = {};
} else {
entryResponse.resource = readResponse.value;
}
}
bundleServiceResponse.batchReadWriteResponses[index] = entryResponse;
});
return BundleGenerator.generateTransactionBundle(this.serverUrl, bundleServiceResponse.batchReadWriteResponses);
}