Skip to content

Instantly share code, notes, and snippets.

@eldhosejoys
Created July 21, 2025 17:12
Show Gist options
  • Save eldhosejoys/a7b579d9ccdf994f7c0b284cf452e45f to your computer and use it in GitHub Desktop.
Save eldhosejoys/a7b579d9ccdf994f7c0b284cf452e45f to your computer and use it in GitHub Desktop.
FHIR JSON validator for the version R4 Schema json from https://hl7.org/fhir/R4/downloads.html and ajv npm library in Express JS
// server.js
const express = require('express');
const Ajv = require('ajv');
const fhirSchema = require('./fhir.schema.json'); // Import the saved FHIR schema
// Initialize Express app
const app = express();
app.use(express.json()); // Middleware to parse JSON bodies
// Initialize Ajv
const ajv = new Ajv({ strict: false });
// --- THIS IS THE FIX ---
// Explicitly add the meta-schema for JSON Schema Draft-06
ajv.addMetaSchema(require('ajv/dist/refs/json-schema-draft-06.json'));
// --------------------
// Add the entire FHIR schema to Ajv.
// Now Ajv knows how to validate this Draft-06 schema.
ajv.addSchema(fhirSchema, 'fhir.schema.json');
// Get the specific validator function for the Patient resource definition.
// The '#/definitions/Patient' is a JSON Pointer to the Patient schema within the main file.
const validatePatient = ajv.getSchema('fhir.schema.json#/definitions/Patient');
// Get the root validator for the entire FHIR schema (for the /Bundle endpoint)
// This will use the "discriminator" to validate any resource type.
const validateFhirResource = ajv.getSchema("http://hl7.org/fhir/json-schema/4.0");
// --- Create the Validation Endpoint ---
app.post('/Patient', (req, res) => {
// The incoming JSON payload is in req.body
const patientPayload = req.body;
// 1. A basic check to ensure the resourceType matches
if (patientPayload.resourceType !== 'Patient') {
return res.status(400).json({
isValid: false,
message: "Validation failed: resourceType must be 'Patient'."
});
}
// 2. Use the compiled validator to check the payload structure
const isValid = validatePatient(patientPayload);
if (isValid) {
// If validation is successful
res.status(200).json({
isValid: true,
message: 'Patient resource is valid.'
});
} else {
// If validation fails, return a 400 Bad Request with the validation errors
res.status(400).json({
isValid: false,
message: 'Patient resource is invalid.',
errors: validatePatient.errors
});
}
});
// --- NEW ENDPOINT for a Bundle Resource ---
app.post('/Bundle', (req, res) => {
const bundlePayload = req.body;
if (!validateFhirResource) {
return res.status(500).send("FHIR resource validator not found");
}
// We can directly validate the bundle. The discriminator will handle the
// specific types of resources within the 'entry' array.
const isValid = validateFhirResource(bundlePayload);
if (isValid) {
res.status(200).json({ isValid: true, message: 'Bundle resource and its contained resources are valid.' });
} else {
res.status(400).json({ isValid: false, message: 'Bundle resource is invalid.', errors: validateFhirResource.errors });
}
});
// Start the server
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
console.log('Post a FHIR Patient JSON object to http://localhost:3000/Patient to validate.');
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment