Skip to content

Commit

Permalink
Engagement/jessica/15544 fhirdata api (#15926)
Browse files Browse the repository at this point in the history
Creates an API that runs a message through specified enrichments, transforms, and filters and provides warnings and errors as a response.
  • Loading branch information
JessicaWNava authored Oct 16, 2024
1 parent f283cf3 commit 204ddee
Show file tree
Hide file tree
Showing 10 changed files with 824 additions and 170 deletions.
45 changes: 45 additions & 0 deletions prime-router/docs/api/reports.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,51 @@ paths:
$ref: '#/components/schemas/Report'
'500':
description: Internal Server Error
/reports/testing/test:
post:
summary: Evaluates a message based off of the receiver settings specified. Returns any errors, filtering, or the message.
security:
- OAuth2: [ system_admin ]
parameters:
- in: query
name: receiverName
description: The name of the receiver to look for in the current environment's settings
schema:
type: string
required: true
example: full-elr
- in: query
name: organizationName
description: The name of the organization to look for the receiver in the current environment's settings
required: true
schema:
type: string
example: me-phd
- in: query
name: senderSchema
description: The path to the sender schema
required: false
schema:
type: string
example: classpath:/metadata/fhir_transforms/senders/SimpleReport/simple-report-sender-transform.yml
requestBody:
description: The message to process
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Report'
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/Report'
'400':
description: Error with one or more filters or finding the receiver.
'500':
description: Internal Server Error
/reports/download:
get:
summary: Downloads a message based on the report id
Expand Down
112 changes: 111 additions & 1 deletion prime-router/src/main/kotlin/azure/ReportFunction.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package gov.cdc.prime.router.azure

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.SerializationFeature
import com.fasterxml.jackson.databind.json.JsonMapper
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import com.github.ajalt.clikt.core.CliktError
import com.google.common.net.HttpHeaders
import com.microsoft.azure.functions.HttpMethod
import com.microsoft.azure.functions.HttpRequestMessage
Expand All @@ -23,7 +25,6 @@ import gov.cdc.prime.router.Sender
import gov.cdc.prime.router.Sender.ProcessingType
import gov.cdc.prime.router.SubmissionReceiver
import gov.cdc.prime.router.UniversalPipelineReceiver
import gov.cdc.prime.router.azure.BlobAccess.Companion.defaultBlobMetadata
import gov.cdc.prime.router.azure.BlobAccess.Companion.getBlobContainer
import gov.cdc.prime.router.azure.db.enums.TaskAction
import gov.cdc.prime.router.azure.db.tables.pojos.ReportFile
Expand All @@ -32,6 +33,7 @@ import gov.cdc.prime.router.azure.observability.event.ReportStreamEventName
import gov.cdc.prime.router.azure.observability.event.ReportStreamEventProperties
import gov.cdc.prime.router.azure.observability.event.ReportStreamEventService
import gov.cdc.prime.router.cli.PIIRemovalCommands
import gov.cdc.prime.router.cli.ProcessFhirCommands
import gov.cdc.prime.router.common.AzureHttpUtils.getSenderIP
import gov.cdc.prime.router.common.Environment
import gov.cdc.prime.router.common.JacksonMapperUtilities
Expand All @@ -43,6 +45,7 @@ import gov.cdc.prime.router.tokens.authenticationFailure
import gov.cdc.prime.router.tokens.authorizationFailure
import kotlinx.serialization.json.Json
import org.apache.logging.log4j.kotlin.Logging
import java.io.File
import java.nio.charset.StandardCharsets
import java.util.UUID

Expand Down Expand Up @@ -120,6 +123,113 @@ class ReportFunction(
return HttpUtilities.unauthorizedResponse(request)
}

/**
* Run a message through the fhirdata cli
*
* @see ../../../docs/api/reports.yml
*/
@FunctionName("processFhirDataRequest")
fun processFhirDataRequest(
@HttpTrigger(
name = "processFhirDataRequest",
methods = [HttpMethod.POST],
authLevel = AuthorizationLevel.ANONYMOUS,
route = "reports/testing/test"
) request: HttpRequestMessage<String?>,
): HttpResponseMessage {
val claims = AuthenticatedClaims.authenticate(request)
if (claims != null && claims.authorized(setOf(Scope.primeAdminScope))) {
val receiverName = request.queryParameters["receiverName"]
val organizationName = request.queryParameters["organizationName"]
val senderSchema = request.queryParameters["senderSchema"]
if (receiverName.isNullOrBlank()) {
return HttpUtilities.badRequestResponse(
request,
"The receiver name is required"
)
}
if (organizationName.isNullOrBlank()) {
return HttpUtilities.badRequestResponse(
request,
"The organization name is required"
)
}
if (request.body.isNullOrBlank()) {
return HttpUtilities.badRequestResponse(
request,
"A message to process must be included in the body"
)
}
val file = File("filename.fhir")
file.createNewFile()
file.bufferedWriter().use { out ->
out.write(request.body)
}

try {
val result = ProcessFhirCommands().processFhirDataRequest(
file,
Environment.get().envName,
receiverName,
organizationName,
senderSchema,
false
)
file.delete()
val message = if (result.message != null) {
result.message.toString()
} else {
null
}
val bundle = if (result.bundle != null) {
result.bundle.toString()
} else {
null
}
return HttpUtilities.okResponse(
request,
ObjectMapper().configure(SerializationFeature.FAIL_ON_SELF_REFERENCES, false).writeValueAsString(
MessageOrBundleStringified(
message,
bundle,
result.senderTransformPassed,
result.senderTransformErrors,
result.senderTransformWarnings,
result.enrichmentSchemaPassed,
result.enrichmentSchemaErrors,
result.senderTransformWarnings,
result.receiverTransformPassed,
result.receiverTransformErrors,
result.receiverTransformWarnings,
result.filterErrors,
result.filtersPassed
)
)
)
} catch (exception: CliktError) {
file.delete()
return HttpUtilities.badRequestResponse(request, "${exception.message}")
}
}
return HttpUtilities.unauthorizedResponse(request)
}

class MessageOrBundleStringified(
var message: String? = null,
var bundle: String? = null,
override var senderTransformPassed: Boolean = true,
override var senderTransformErrors: MutableList<String> = mutableListOf(),
override var senderTransformWarnings: MutableList<String> = mutableListOf(),
override var enrichmentSchemaPassed: Boolean = true,
override var enrichmentSchemaErrors: MutableList<String> = mutableListOf(),
override var enrichmentSchemaWarnings: MutableList<String> = mutableListOf(),
override var receiverTransformPassed: Boolean = true,
override var receiverTransformErrors: MutableList<String> = mutableListOf(),
override var receiverTransformWarnings: MutableList<String> = mutableListOf(),
override var filterErrors: MutableList<String> = mutableListOf(),
override var filtersPassed: Boolean = true,
) : ProcessFhirCommands.MessageOrBundleParent()

/**
* Moved the logic to a separate function for testing purposes
*/
Expand Down
Loading

0 comments on commit 204ddee

Please sign in to comment.