Skip to content

Commit 2a9e333

Browse files
committed
feat(routes): add hl7v2-to-json route
1 parent c2cc116 commit 2a9e333

File tree

7 files changed

+176
-1
lines changed

7 files changed

+176
-1
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Docsmith is a RESTful API, built using Node.js and the [Fastify](https://fastify
1818
| DOC | TXT | DOT file variant supported |
1919
| DOCX | HTML | DOCM, DOTM, and DOTX file variants supported |
2020
| DOCX | TXT | DOCM, DOTM, and DOTX file variants supported |
21+
| HL7v2 | JSON | |
2122
| HTML | TXT | |
2223
| PDF | HTML | |
2324
| PDF | TXT | Scanned documents supported using OCR |

package-lock.json

Lines changed: 16 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
"@fastify/static": "^6.10.2",
101101
"@fastify/swagger": "^8.5.1",
102102
"@fastify/under-pressure": "^8.2.0",
103+
"@redoxengine/redox-hl7-v2": "^1.0.1",
103104
"cfb": "^1.2.2",
104105
"clean-css": "^5.3.2",
105106
"cssesc": "^3.0.0",

src/config/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,11 @@ async function getConfig() {
293293
description:
294294
"Endpoints used for the conversion of DOTX documents",
295295
},
296+
{
297+
name: "HL7v2",
298+
description:
299+
"Endpoints used for the conversion of HL7 v2.x messages",
300+
},
296301
{
297302
name: "HTML",
298303
description:

src/plugins/hl7v2-to-json/index.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
const fp = require("fastify-plugin");
2+
const hl7v2 = require("@redoxengine/redox-hl7-v2");
3+
4+
/**
5+
* @author Frazer Smith
6+
* @description Pre-handler plugin that uses redox-hl7-v2 to convert string containing
7+
* HL7 v2.x in `req.body` to JSON.
8+
* `req` object is decorated with `conversionResults.body` holding the converted document.
9+
* @param {object} server - Fastify instance.
10+
*/
11+
async function plugin(server) {
12+
const parser = new hl7v2.Parser();
13+
14+
server.addHook("onRequest", async (req) => {
15+
req.conversionResults = { body: undefined };
16+
});
17+
18+
server.addHook("preHandler", async (req) => {
19+
/**
20+
* `htmlToText` function still attempts to parse empty bodies/input or invalid HTML
21+
* and produces results, so catch them here
22+
*/
23+
// if (req.body === undefined || Object.keys(req.body).length === 0) {
24+
// throw server.httpErrors.badRequest();
25+
// }
26+
27+
try {
28+
const results = parser.parse(req.body);
29+
req.conversionResults.body = results;
30+
} catch {
31+
/**
32+
* redox-hl7-v2 will throw if the HL7 v2 message provided
33+
* by client is malformed or invalid, thus client error code
34+
*/
35+
throw server.httpErrors.badRequest();
36+
}
37+
});
38+
}
39+
40+
module.exports = fp(plugin, {
41+
fastify: "4.x",
42+
name: "hl7v2ToJson",
43+
dependencies: ["@fastify/sensible"],
44+
});

src/routes/hl7v2/json/index.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Import plugins
2+
const cors = require("@fastify/cors");
3+
const hl7v2ToJson = require("../../../plugins/hl7v2-to-json");
4+
5+
const { hl7v2ToJsonPostSchema } = require("./schema");
6+
7+
const accepts = hl7v2ToJsonPostSchema.produces;
8+
9+
/**
10+
* @author Frazer Smith
11+
* @description Sets routing options for server.
12+
* @param {object} server - Fastify instance.
13+
* @param {object} options - Route config values.
14+
* @param {*=} options.bearerTokenAuthKeys - Apply `bearerToken` security scheme to route if defined.
15+
* @param {object} options.cors - CORS settings.
16+
*/
17+
async function route(server, options) {
18+
if (options.bearerTokenAuthKeys) {
19+
hl7v2ToJsonPostSchema.security = [{ bearerToken: [] }];
20+
hl7v2ToJsonPostSchema.response[401] = {
21+
$ref: "responses#/properties/unauthorized",
22+
description: "Unauthorized",
23+
};
24+
}
25+
26+
server.addContentTypeParser(
27+
hl7v2ToJsonPostSchema.consumes,
28+
{ parseAs: "string" },
29+
async (_req, payload) => {
30+
/**
31+
* The Content-Type header can be spoofed so is not trusted implicitly,
32+
* this checks the payload is an HL7 v2.x message
33+
*/
34+
if (!payload.startsWith("MSH")) {
35+
throw server.httpErrors.unsupportedMediaType();
36+
}
37+
38+
return payload;
39+
}
40+
);
41+
42+
// Register plugins
43+
await server
44+
// Enable CORS if options passed
45+
.register(cors, {
46+
...options.cors,
47+
methods: ["POST"],
48+
})
49+
.register(hl7v2ToJson);
50+
51+
server.route({
52+
method: "POST",
53+
url: "/",
54+
schema: hl7v2ToJsonPostSchema,
55+
onRequest: async (req) => {
56+
if (
57+
// Catch unsupported Accept header media types
58+
!req.accepts().type(accepts)
59+
) {
60+
throw server.httpErrors.notAcceptable();
61+
}
62+
},
63+
handler: (req, res) => {
64+
res.send(req.conversionResults.body);
65+
},
66+
});
67+
}
68+
69+
module.exports = route;

src/routes/hl7v2/json/schema.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
const S = require("fluent-json-schema");
2+
3+
const tags = ["HL7 v2.x"];
4+
5+
/**
6+
* Fastify uses AJV for JSON Schema Validation,
7+
* see https://fastify.io/docs/latest/Reference/Validation-and-Serialization/
8+
*
9+
* Input validation protects against XSS, HPP, prototype pollution,
10+
* and most other injection attacks.
11+
*/
12+
const hl7v2ToJsonPostSchema = {
13+
tags,
14+
summary: "Convert HL7 v2.x message to JSON",
15+
description:
16+
"Returns the result of converting an HL7 v2.x message to JSON format.",
17+
operationId: "postHl7v2ToJson",
18+
consumes: ["text/hl7v2"],
19+
produces: ["application/json"],
20+
response: {
21+
200: S.object().additionalProperties(true),
22+
400: S.ref("responses#/properties/badRequest").description(
23+
"Bad Request"
24+
),
25+
406: S.ref("responses#/properties/notAcceptable").description(
26+
"Not Acceptable"
27+
),
28+
415: S.ref("responses#/properties/unsupportedMediaType").description(
29+
"Unsupported Media Type"
30+
),
31+
429: S.ref("responses#/properties/tooManyRequests").description(
32+
"Too Many Requests"
33+
),
34+
503: S.ref("responses#/properties/serviceUnavailable").description(
35+
"Service Unavailable"
36+
),
37+
},
38+
};
39+
40+
module.exports = { hl7v2ToJsonPostSchema };

0 commit comments

Comments
 (0)