164 lines
3.8 KiB
TypeScript
164 lines
3.8 KiB
TypeScript
/**
|
|
* FHIR Patient API - Instance Endpoints
|
|
* GET /api/fhir/Patient/[id] - Read patient
|
|
* PUT /api/fhir/Patient/[id] - Update patient
|
|
*/
|
|
|
|
import { NextRequest, NextResponse } from 'next/server';
|
|
import { supabaseAdmin } from '@/lib/supabase/server';
|
|
import {
|
|
dbPatientToFHIR,
|
|
fhirPatientToDB,
|
|
createOperationOutcome,
|
|
validateFHIRResource,
|
|
} from '@/lib/fhir';
|
|
import type { FHIRPatient } from '@/lib/fhir';
|
|
|
|
/**
|
|
* GET /api/fhir/Patient/[id]
|
|
* Returns a single FHIR Patient resource
|
|
*/
|
|
export async function GET(
|
|
request: NextRequest,
|
|
{ params }: { params: { id: string } }
|
|
) {
|
|
try {
|
|
const { id } = params;
|
|
|
|
// Query patient by ID
|
|
const { data: patient, error } = await supabaseAdmin
|
|
.from('patients')
|
|
.select('*')
|
|
.eq('id', id)
|
|
.single();
|
|
|
|
if (error || !patient) {
|
|
return NextResponse.json(
|
|
createOperationOutcome(
|
|
'error',
|
|
'not-found',
|
|
`Patient with id ${id} not found`
|
|
),
|
|
{ status: 404 }
|
|
);
|
|
}
|
|
|
|
// Transform to FHIR resource
|
|
const fhirPatient = dbPatientToFHIR(patient);
|
|
|
|
return NextResponse.json(fhirPatient);
|
|
} catch (error) {
|
|
return NextResponse.json(
|
|
createOperationOutcome(
|
|
'error',
|
|
'exception',
|
|
error instanceof Error ? error.message : 'Unknown error'
|
|
),
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* PUT /api/fhir/Patient/[id]
|
|
* Updates a patient from FHIR Patient resource
|
|
*/
|
|
export async function PUT(
|
|
request: NextRequest,
|
|
{ params }: { params: { id: string } }
|
|
) {
|
|
try {
|
|
const { id } = params;
|
|
const fhirPatient: FHIRPatient = await request.json();
|
|
|
|
// Validate required fields
|
|
const validation = validateFHIRResource(fhirPatient, [
|
|
'resourceType',
|
|
'name',
|
|
'gender',
|
|
'birthDate',
|
|
]);
|
|
|
|
if (!validation.valid) {
|
|
return NextResponse.json(
|
|
createOperationOutcome('error', 'invalid', validation.errors.join(', ')),
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
// Verify resourceType
|
|
if (fhirPatient.resourceType !== 'Patient') {
|
|
return NextResponse.json(
|
|
createOperationOutcome(
|
|
'error',
|
|
'invalid',
|
|
`Expected resourceType "Patient", got "${fhirPatient.resourceType}"`
|
|
),
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
// Verify ID matches
|
|
if (fhirPatient.id && fhirPatient.id !== id) {
|
|
return NextResponse.json(
|
|
createOperationOutcome(
|
|
'error',
|
|
'invalid',
|
|
`ID in URL (${id}) does not match ID in resource (${fhirPatient.id})`
|
|
),
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
// Check if patient exists
|
|
const { data: existingPatient, error: fetchError } = await supabaseAdmin
|
|
.from('patients')
|
|
.select('id')
|
|
.eq('id', id)
|
|
.single();
|
|
|
|
if (fetchError || !existingPatient) {
|
|
return NextResponse.json(
|
|
createOperationOutcome(
|
|
'error',
|
|
'not-found',
|
|
`Patient with id ${id} not found`
|
|
),
|
|
{ status: 404 }
|
|
);
|
|
}
|
|
|
|
// Transform to database format
|
|
const patientUpdate = fhirPatientToDB(fhirPatient);
|
|
|
|
// Update in database
|
|
const { data: updatedPatient, error: updateError } = await supabaseAdmin
|
|
.from('patients')
|
|
.update(patientUpdate)
|
|
.eq('id', id)
|
|
.select()
|
|
.single();
|
|
|
|
if (updateError) {
|
|
return NextResponse.json(
|
|
createOperationOutcome('error', 'processing', updateError.message),
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
|
|
// Return updated patient as FHIR resource
|
|
const fhirResponse = dbPatientToFHIR(updatedPatient);
|
|
|
|
return NextResponse.json(fhirResponse);
|
|
} catch (error) {
|
|
return NextResponse.json(
|
|
createOperationOutcome(
|
|
'error',
|
|
'exception',
|
|
error instanceof Error ? error.message : 'Unknown error'
|
|
),
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|