Skip to content

Commit

Permalink
dedupe / reorg files
Browse files Browse the repository at this point in the history
  • Loading branch information
fzhao99 committed Feb 18, 2025
1 parent 06c3f29 commit ae193c3
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 160 deletions.
18 changes: 18 additions & 0 deletions query-connector/src/app/api/query/error-handling-service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { OperationOutcome } from "fhir/r4";
import { NextResponse } from "next/server";

/**
* Handles a request error by returning an OperationOutcome with a diagnostics message.
Expand All @@ -21,3 +22,20 @@ export async function handleRequestError(
};
return OperationOutcome;
}

export async function handleAndReturnError(error: unknown, status = 500) {
let diagnostics_message = "An error has occurred";

let OperationOutcome;
if (typeof error === "string") {
diagnostics_message = `${diagnostics_message}: ${error}`;
OperationOutcome = await handleRequestError(error as string);
} else {
if (error instanceof Error) {
diagnostics_message = `${diagnostics_message}: ${error}`;
}
OperationOutcome = await handleRequestError(diagnostics_message);
}
console.error(error);
return NextResponse.json(OperationOutcome, { status: status });
}
81 changes: 0 additions & 81 deletions query-connector/src/app/api/query/hl7v2/route.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { Patient } from "fhir/r4";
import { FormatPhoneAsDigits } from "@/app/shared/format-service";
import { USE_CASES, USE_CASE_DETAILS } from "@/app/shared/constants";

export type PatientIdentifiers = {
first_name?: string;
Expand Down Expand Up @@ -69,12 +70,13 @@ export async function parseMRNs(
patient: Patient,
): Promise<(string | undefined)[] | undefined> {
if (patient.identifier) {
const mrnIdentifiers = patient.identifier.filter((id) =>
id.type?.coding?.some(
(coding) =>
coding.system === "http://terminology.hl7.org/CodeSystem/v2-0203" &&
coding.code === "MR",
),
const mrnIdentifiers = patient.identifier.filter(
(id) =>
id.type?.coding?.some(
(coding) =>
coding.system === "http://terminology.hl7.org/CodeSystem/v2-0203" &&
coding.code === "MR",
),
);
return mrnIdentifiers.map((id) => id.value);
}
Expand All @@ -99,3 +101,25 @@ export async function parsePhoneNumbers(
return phoneNumbers.map((contactPoint) => contactPoint.value);
}
}

export function parseHL7FromRequestBody(requestText: string) {
let result = requestText;

// strip the leading { / closing } if they exist
if (requestText[0] === "{" || requestText[requestText.length - 1] === "}") {
const leadingClosingBraceRegex = /\{([\s\S]*)\}/;
const requestMatch = requestText.match(leadingClosingBraceRegex);
if (requestMatch) {
console.log(requestMatch[1]);
result = requestMatch[1].trim();
}
}
return result;
}

export function mapDeprecatedUseCaseToId(use_case: string | null) {
if (use_case === null) return null;
const potentialUseCaseMatch = USE_CASE_DETAILS[use_case as USE_CASES];
const queryId = potentialUseCaseMatch?.id ?? null;
return queryId;
}
161 changes: 88 additions & 73 deletions query-connector/src/app/api/query/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { NextRequest, NextResponse } from "next/server";
import { handleRequestError } from "./error-handling-service";
import {
handleAndReturnError,
handleRequestError,
} from "./error-handling-service";
import {
makeFhirQuery,
QueryRequest,
Expand All @@ -16,9 +19,16 @@ import {
INVALID_QUERY,
USE_CASE_DETAILS,
USE_CASES,
INVALID_MESSAGE_FORMAT,
HL7_BODY_MISFORMAT,
} from "@/app/shared/constants";
import { getFhirServerNames } from "@/app/shared/database-service";
import { parsePatientDemographics } from "./fhir/parsers";
import {
mapDeprecatedUseCaseToId,
parseHL7FromRequestBody,
parsePatientDemographics,
} from "./parsers";
import { Message } from "node-hl7-client";

/**
* @swagger
Expand Down Expand Up @@ -154,7 +164,7 @@ export async function GET(request: NextRequest) {
* @swagger
* /api/query:
* post:
* description: A POST endpoint that accepts a FHIR patient resource in the request body to execute a query within the Query Connector
* description: A POST endpoint that accepts a FHIR patient resource or an HL7v2 message in the request body to execute a query within the Query Connector
* parameters:
* - name: fhir_server
* in: query
Expand All @@ -170,6 +180,13 @@ export async function GET(request: NextRequest) {
* schema:
* type: string
* example: cf580d8d-cc7b-4eae-8a0d-96c36f9222e3
* - name: message_format
* in: query
* description: Whether the request body contents are HL7 or FHIR formatted messages
* schema:
* type: string
* enum: [HL7, FHIR]
* example: FHIR
* requestBody:
* required: true
* content:
Expand All @@ -187,28 +204,6 @@ export async function GET(request: NextRequest) {
* @returns Response with QueryResponse.
*/
export async function POST(request: NextRequest) {
let requestBody;

try {
requestBody = await request.json();

// Check if requestBody is a patient resource
if (requestBody.resourceType !== "Patient") {
const OperationOutcome = await handleRequestError(
RESPONSE_BODY_IS_NOT_PATIENT_RESOURCE,
);
return NextResponse.json(OperationOutcome);
}
} catch (error: unknown) {
let diagnostics_message = "An error occurred.";
console.error(error);
if (error instanceof Error) {
diagnostics_message = `${error.message}`;
}
const OperationOutcome = await handleRequestError(diagnostics_message);
return NextResponse.json(OperationOutcome, { status: 500 });
}

// Extract id and fhir_server from nextUrl
const params = request.nextUrl.searchParams;
//deprecated, prefer id
Expand All @@ -219,57 +214,84 @@ export async function POST(request: NextRequest) {

const id = id_param ? id_param : mapDeprecatedUseCaseToId(use_case_param);

if (!id || !fhir_server || !requestBody) {
const OperationOutcome = await handleRequestError(MISSING_API_QUERY_PARAM);
return NextResponse.json(OperationOutcome, {
status: 500,
});
if (!id || !fhir_server) {
return await handleAndReturnError(MISSING_API_QUERY_PARAM);
} else if (!Object.values(fhirServers).includes(fhir_server)) {
const OperationOutcome = await handleRequestError(INVALID_FHIR_SERVERS);
return NextResponse.json(OperationOutcome, {
status: 500,
});
return await handleAndReturnError(INVALID_FHIR_SERVERS);
}

const queryResults = await getSavedQueryById(id);

if (queryResults === undefined) {
const OperationOutcome = await handleRequestError(INVALID_QUERY);
return NextResponse.json(OperationOutcome, {
status: 500,
});
return handleAndReturnError(INVALID_QUERY);
}

// try getting params straight from requestBody
const given = requestBody["given"];
const family = requestBody["family"];
const dob = requestBody["dob"];
const mrn = requestBody["mrn"];
const phone = requestBody["phone"];
const noParamsDefined = [given, family, dob, mrn, phone].every(
(e) => e === undefined,
);
// check message format of body, default to FHIR
const messageFormat = params.get("message_format") ?? "FHIR";
if (messageFormat !== "FHIR" && messageFormat !== "HL7") {
return await handleAndReturnError(INVALID_MESSAGE_FORMAT);
}

// Parse patient identifiers from a potential FHIR resource
const PatientIdentifiers = await parsePatientDemographics(requestBody);
let QueryRequest: QueryRequest;
if (messageFormat === "HL7") {
try {
let requestText = await request.text();

if (Object.keys(PatientIdentifiers).length === 0 && noParamsDefined) {
const OperationOutcome = await handleRequestError(
MISSING_PATIENT_IDENTIFIERS,
);
return NextResponse.json(OperationOutcome, { status: 400 });
}
const parsedMessage = new Message({
text: parseHL7FromRequestBody(requestText),
});

// Add params & patient identifiers to QueryName
const QueryRequest: QueryRequest = {
query_name: queryResults.query_name,
fhir_server: fhir_server,
first_name: PatientIdentifiers?.first_name ?? given,
last_name: PatientIdentifiers?.last_name ?? family,
dob: PatientIdentifiers?.dob ?? dob,
mrn: PatientIdentifiers?.mrn ?? mrn,
phone: PatientIdentifiers?.phone ?? phone,
};
console.log(
parsedMessage.get("PID.3.1").toString(),
parsedMessage.get("NK1.5.1").toString(),
);
QueryRequest = {
query_name: queryResults?.query_name,
fhir_server: fhir_server,
first_name: parsedMessage.get("PID.5.2").toString() || "",
last_name: parsedMessage.get("PID.5.1").toString() || "",
dob: parsedMessage.get("PID.7.1").toString() || "",
mrn: parsedMessage.get("PID.3.1").toString() || "",
phone: parsedMessage.get("NK1.5.1").toString() || "",
};
} catch (error: unknown) {
return await handleAndReturnError(error);
}
} else {
try {
const requestBodyToCheck = await request.json();
// try extracting patient identifiers out of the request body from a potential
// FHIR message or as raw params
if (
requestBodyToCheck.resourceType &&
requestBodyToCheck.resourceType !== "Patient"
) {
return await handleAndReturnError(
RESPONSE_BODY_IS_NOT_PATIENT_RESOURCE,
);
}

// Parse patient identifiers from a potential FHIR resource
const PatientIdentifiers =
await parsePatientDemographics(requestBodyToCheck);

if (Object.keys(PatientIdentifiers).length === 0) {
return await handleAndReturnError(MISSING_PATIENT_IDENTIFIERS, 400);
}

// Add params & patient identifiers to QueryName
QueryRequest = {
query_name: queryResults.query_name,
fhir_server: fhir_server,
first_name: PatientIdentifiers?.first_name,
last_name: PatientIdentifiers?.last_name,
dob: PatientIdentifiers?.dob,
mrn: PatientIdentifiers?.mrn,
phone: PatientIdentifiers?.phone,
};
} catch (error: unknown) {
return await handleAndReturnError(error);
}
}

const QueryResponse: QueryResponse = await makeFhirQuery(QueryRequest);

Expand All @@ -280,10 +302,3 @@ export async function POST(request: NextRequest) {
status: 200,
});
}

function mapDeprecatedUseCaseToId(use_case: string | null) {
if (use_case === null) return null;
const potentialUseCaseMatch = USE_CASE_DETAILS[use_case as USE_CASES];
const queryId = potentialUseCaseMatch?.id ?? null;
return queryId;
}
4 changes: 4 additions & 0 deletions query-connector/src/app/shared/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,10 @@ export const INVALID_FHIR_SERVERS = `Invalid fhir_server. Please provide a valid
export const RESPONSE_BODY_IS_NOT_PATIENT_RESOURCE =
"Request body is not a Patient resource.";
export const MISSING_API_QUERY_PARAM = "Missing id or fhir_server.";
export const INVALID_MESSAGE_FORMAT =
"Invalid message format. Format parameter needs to be either 'HL7' or 'FHIR'";
export const HL7_BODY_MISFORMAT =
"Invalid HL7 request. Please add your HL7 message to the request body in between curly braces like so - { YOUR MESSAGE HERE } ";
export const MISSING_PATIENT_IDENTIFIERS =
"No patient identifiers to parse from requestBody.";

Expand Down

0 comments on commit ae193c3

Please sign in to comment.