From 8d9adb35c9bb9c4dd1efafc5fb2a61918a7dbae7 Mon Sep 17 00:00:00 2001 From: chinlinlee Date: Wed, 3 Jan 2024 19:41:47 +0800 Subject: [PATCH] feat: add dicom convert to fhir API --- api/fhir-convert/controller/dicom-to-fhir.js | 38 +++++++++++++ .../service/fhir-convert.service.js | 38 +++++++++++++ api/fhir-convert/index.js | 54 +++++++++++++++++++ docs/swagger/openapi.json | 40 +++++++++++++- routes.js | 2 + 5 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 api/fhir-convert/controller/dicom-to-fhir.js create mode 100644 api/fhir-convert/controller/service/fhir-convert.service.js create mode 100644 api/fhir-convert/index.js diff --git a/api/fhir-convert/controller/dicom-to-fhir.js b/api/fhir-convert/controller/dicom-to-fhir.js new file mode 100644 index 00000000..9bba08db --- /dev/null +++ b/api/fhir-convert/controller/dicom-to-fhir.js @@ -0,0 +1,38 @@ +const { ApiErrorArrayHandler } = require("@error/api-errors.handler"); +const { Controller } = require("@root/api/controller.class"); +const { FhirConvertService } = require("./service/fhir-convert.service"); +const { ApiLogger } = require("@root/utils/logs/api-logger"); + + +class FhirConvertController extends Controller { + constructor(req, res) { + super(req, res); + this.apiLogger = new ApiLogger(req, "fhir-convert"); + this.apiLogger.addTokenValue(); + } + + async mainProcess() { + let fhirConvertService = new FhirConvertService(this.request, this.response); + try { + let fhirJson = await fhirConvertService.convert(); + return this.response + .set("content-type", "application/json") + .status(200) + .json(fhirJson); + } catch (e) { + let apiErrorArrayHandler = new ApiErrorArrayHandler(this.response, this.apiLogger, e); + return apiErrorArrayHandler.doErrorResponse(); + } + } +} + +/** + * + * @param {import('express').Request} req + * @param {import('express').Response} res + */ +module.exports = async function (req, res) { + let controller = new FhirConvertController(req, res); + + await controller.doPipeline(); +}; diff --git a/api/fhir-convert/controller/service/fhir-convert.service.js b/api/fhir-convert/controller/service/fhir-convert.service.js new file mode 100644 index 00000000..75df5cc2 --- /dev/null +++ b/api/fhir-convert/controller/service/fhir-convert.service.js @@ -0,0 +1,38 @@ +const { DicomJsonToFhir } = require("dicomjson-to-fhir"); +const dicomToJson = require("../dicom-to-fhir"); +const { dcm2jsonV8 } = require("@models/DICOM/dcmtk"); +const { raccoonConfig } = require("@root/config-class"); +const Joi = require("joi"); +const { DicomWebServiceError, DicomWebStatusCodes } = require("@error/dicom-web-service"); + +const fileSchema = Joi.object({ + files: Joi.object({ + file: Joi.object({ + filepath: Joi.string().required() + }).required() + }).required() +}); + +class FhirConvertService { + constructor(req, res) { + this.request = req; + this.response = res; + } + + async convert() { + let { value, error } = fileSchema.validate(this.request, { allowUnknown : true}); + if (error) { + throw new DicomWebServiceError(DicomWebStatusCodes.InvalidArgumentValue, error.details[0].message, 400); + } + let dicomJson = await dcm2jsonV8.exec(this.request.files.file.filepath); + let protocol = this.request.secure ? "https" : "http"; + let dicomJsonToFhir = new DicomJsonToFhir( + dicomJson, + "raccoon-dicom-web-server", + `${protocol}://${this.request.headers.host}/${raccoonConfig.dicomWebConfig.apiPath}/studies` + ); + return dicomJsonToFhir.getFhirJson(); + } +} + +module.exports.FhirConvertService = FhirConvertService; \ No newline at end of file diff --git a/api/fhir-convert/index.js b/api/fhir-convert/index.js new file mode 100644 index 00000000..03a66f1f --- /dev/null +++ b/api/fhir-convert/index.js @@ -0,0 +1,54 @@ +/** + * Route /fhir-convert + * Implement `DICOM convert to FHIR ImagingStudy, Patient, Endpoint` + * + * @author Chin-Lin Lee + */ + +const Joi = require("joi"); +const { validateByJoi } = require("../validator"); +const express = require("express"); +const router = express.Router(); +const formidable = require("formidable"); + +const formMiddleWare = async (req, res, next) => { + const form = formidable({}); + + form.parse(req, (err, fields, files) => { + if (err) { + next(err); + return; + } + req.fields = fields; + req.files = files; + next(); + }); +}; + +/** + * @openapi + * /fhir-convert: + * post: + * tags: + * - fhir-convert + * description: Convert DICOM to FHIR ImagingStudy, Patient, Endpoint + * requestBody: + * content: + * multipart/form-data: + * schema: + * type: object + * properties: + * file: + * type: string + * format: binary + * encoding: + * file: + * contentType: application/dicom; + * responses: + * "200": + * description: The DICOM instance store successfully + */ +router.post("/", formMiddleWare, require("./controller/dicom-to-fhir")); + + +module.exports = router; \ No newline at end of file diff --git a/docs/swagger/openapi.json b/docs/swagger/openapi.json index 607403b8..9265bb51 100644 --- a/docs/swagger/openapi.json +++ b/docs/swagger/openapi.json @@ -152,7 +152,12 @@ "content": { "application/dicom+json": { "schema": { - "$ref": "#/components/schemas/PatientRequiredMatchingAttributes" + "type": "object", + "properties": { + "patientID": { + "type": "string" + } + } } } } @@ -1298,6 +1303,39 @@ } } }, + "/fhir-convert": { + "post": { + "tags": [ + "fhir-convert" + ], + "description": "Convert DICOM to FHIR ImagingStudy, Patient, Endpoint", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "file": { + "type": "string", + "format": "binary" + } + } + }, + "encoding": { + "file": { + "contentType": "application/dicom;" + } + } + } + } + }, + "responses": { + "200": { + "description": "The DICOM instance store successfully" + } + } + } + }, "/wado": { "get": { "tags": [ diff --git a/routes.js b/routes.js index e6997140..c11fe1e4 100644 --- a/routes.js +++ b/routes.js @@ -32,4 +32,6 @@ module.exports = function (app) { app.use("/dicom-web", require("./api/dicom-web/pam-rs.route")); app.use("/wado", require("./api/WADO-URI")); + + app.use("/fhir-convert", require("./api/fhir-convert")); };