Skip to content

Commit

Permalink
feat(routes): add hl7v2-to-json route
Browse files Browse the repository at this point in the history
  • Loading branch information
Fdawgs committed May 31, 2023
1 parent 0d069b1 commit 64a496e
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Docsmith is a RESTful API, built using Node.js and the [Fastify](https://fastify
| DOC | TXT | DOT file variant supported |
| DOCX | HTML | DOCM, DOTM, and DOTX file variants supported |
| DOCX | TXT | DOCM, DOTM, and DOTX file variants supported |
| HL7v2 | JSON | |
| HTML | TXT | |
| PDF | HTML | |
| PDF | TXT | Scanned documents supported using OCR |
Expand Down
17 changes: 16 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
"@fastify/static": "^6.10.2",
"@fastify/swagger": "^8.5.1",
"@fastify/under-pressure": "^8.2.0",
"@redoxengine/redox-hl7-v2": "^1.0.1",
"cfb": "^1.2.2",
"clean-css": "^5.3.2",
"cssesc": "^3.0.0",
Expand Down
5 changes: 5 additions & 0 deletions src/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,11 @@ async function getConfig() {
description:
"Endpoints used for the conversion of DOTX documents",
},
{
name: "HL7v2",
description:
"Endpoints used for the conversion of HL7 v2.x messages",
},
{
name: "HTML",
description:
Expand Down
44 changes: 44 additions & 0 deletions src/plugins/hl7v2-to-json/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const fp = require("fastify-plugin");
const hl7v2 = require("@redoxengine/redox-hl7-v2");

/**
* @author Frazer Smith
* @description Pre-handler plugin that uses redox-hl7-v2 to convert string containing
* HL7 v2.x in `req.body` to JSON.
* `req` object is decorated with `conversionResults.body` holding the converted document.
* @param {object} server - Fastify instance.
*/
async function plugin(server) {
const parser = new hl7v2.Parser();

server.addHook("onRequest", async (req) => {
req.conversionResults = { body: undefined };
});

server.addHook("preHandler", async (req) => {
/**
* `htmlToText` function still attempts to parse empty bodies/input or invalid HTML
* and produces results, so catch them here
*/
// if (req.body === undefined || Object.keys(req.body).length === 0) {
// throw server.httpErrors.badRequest();
// }

try {
const results = parser.parse(req.body);
req.conversionResults.body = results;
} catch {
/**
* redox-hl7-v2 will throw if the HL7 v2 message provided
* by client is malformed or invalid, thus client error code
*/
throw server.httpErrors.badRequest();
}
});
}

module.exports = fp(plugin, {
fastify: "4.x",
name: "hl7v2ToJson",
dependencies: ["@fastify/sensible"],
});
69 changes: 69 additions & 0 deletions src/routes/hl7v2/json/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Import plugins
const cors = require("@fastify/cors");
const hl7v2ToJson = require("../../../plugins/hl7v2-to-json");

const { hl7v2ToJsonPostSchema } = require("./schema");

const accepts = hl7v2ToJsonPostSchema.produces;

/**
* @author Frazer Smith
* @description Sets routing options for server.
* @param {object} server - Fastify instance.
* @param {object} options - Route config values.
* @param {*=} options.bearerTokenAuthKeys - Apply `bearerToken` security scheme to route if defined.
* @param {object} options.cors - CORS settings.
*/
async function route(server, options) {
if (options.bearerTokenAuthKeys) {
hl7v2ToJsonPostSchema.security = [{ bearerToken: [] }];
hl7v2ToJsonPostSchema.response[401] = {
$ref: "responses#/properties/unauthorized",
description: "Unauthorized",
};
}

server.addContentTypeParser(
hl7v2ToJsonPostSchema.consumes,
{ parseAs: "string" },
async (_req, payload) => {
/**
* The Content-Type header can be spoofed so is not trusted implicitly,
* this checks the payload is an HL7 v2.x message
*/
if (!payload.startsWith("MSH")) {
throw server.httpErrors.unsupportedMediaType();
}

return payload;
}
);

// Register plugins
await server
// Enable CORS if options passed
.register(cors, {
...options.cors,
methods: ["POST"],
})
.register(hl7v2ToJson);

server.route({
method: "POST",
url: "/",
schema: hl7v2ToJsonPostSchema,
onRequest: async (req) => {
if (
// Catch unsupported Accept header media types
!req.accepts().type(accepts)
) {
throw server.httpErrors.notAcceptable();
}
},
handler: (req, res) => {
res.send(req.conversionResults.body);
},
});
}

module.exports = route;
40 changes: 40 additions & 0 deletions src/routes/hl7v2/json/schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const S = require("fluent-json-schema");

const tags = ["HL7 v2.x"];

/**
* Fastify uses AJV for JSON Schema Validation,
* see https://fastify.io/docs/latest/Reference/Validation-and-Serialization/
*
* Input validation protects against XSS, HPP, prototype pollution,
* and most other injection attacks.
*/
const hl7v2ToJsonPostSchema = {
tags,
summary: "Convert HL7 v2.x message to JSON",
description:
"Returns the result of converting an HL7 v2.x message to JSON format.",
operationId: "postHl7v2ToJson",
consumes: ["text/hl7v2"],
produces: ["application/json"],
response: {
200: S.object().additionalProperties(true),
400: S.ref("responses#/properties/badRequest").description(
"Bad Request"
),
406: S.ref("responses#/properties/notAcceptable").description(
"Not Acceptable"
),
415: S.ref("responses#/properties/unsupportedMediaType").description(
"Unsupported Media Type"
),
429: S.ref("responses#/properties/tooManyRequests").description(
"Too Many Requests"
),
503: S.ref("responses#/properties/serviceUnavailable").description(
"Service Unavailable"
),
},
};

module.exports = { hl7v2ToJsonPostSchema };

0 comments on commit 64a496e

Please sign in to comment.