async processTransaction()

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);
    }