From b5bea3f2f03e619e38bd0ffae9261e44d1f09be1 Mon Sep 17 00:00:00 2001 From: Bishal Date: Mon, 1 Jul 2024 20:45:55 +0000 Subject: [PATCH] added the message validation parameter --- package.json | 4 +++ template/src/api/middlewares/error-logger.js | 5 +++- template/src/api/routes/route.js | 23 +++++++++-------- template/src/lib/message-validator.js | 27 ++++++++++++++++---- 4 files changed, 42 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 0c52f5ab..55476028 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,10 @@ "certFilesDir": { "description": "Directory where application certificates are located. This parameter is needed when you use X509 security scheme and your cert files are not located in the root of your application.", "default": "./" + }, + "messageRuntimeValidation": { + "description": "Enable or disable runtime validation of message identifiers.", + "default": true } }, "nonRenderableFiles": [ diff --git a/template/src/api/middlewares/error-logger.js b/template/src/api/middlewares/error-logger.js index 8fca17a1..951bdd71 100644 --- a/template/src/api/middlewares/error-logger.js +++ b/template/src/api/middlewares/error-logger.js @@ -1,8 +1,11 @@ -const { red, gray } = require('chalk'); +const { red, gray, green } = require('chalk'); module.exports = (err, message, next) => { if (err.name === 'AsyncAPIValidationError') { console.error(red(`❗ Message Rejected. ${err.message}`)); + if(err.warning) { + console.warn(green(`⛔ ${err.warning}`)); + } } else { console.error(red(`❗ ${err.message}`)); if (err.stack) diff --git a/template/src/api/routes/route.js b/template/src/api/routes/route.js index 62d99baa..a18c728e 100644 --- a/template/src/api/routes/route.js +++ b/template/src/api/routes/route.js @@ -2,7 +2,7 @@ import { File } from '@asyncapi/generator-react-sdk'; import { camelCase, convertToFilename, toHermesTopic } from '../../../../helpers/index'; -function receiveHandler(operation, channelName, channelAddress, isSpecV3) { +function receiveHandler(operation, channelName, channelAddress, isSpecV3, messageRuntimeValidation) { if (!operation.isReceive()) { return ''; } @@ -22,7 +22,7 @@ function receiveHandler(operation, channelName, channelAddress, isSpecV3) { ${ operation.messages().all().map(message => `try { - nValidated = await validateMessage(message.payload,'${ channelAddress }','${ message.name() }','publish', nValidated); + nValidated = await validateMessage(message.payload,'${ channelAddress }','${ message.name() }','publish', ${messageRuntimeValidation}, nValidated); } catch { };`).join('\n') } @@ -31,7 +31,7 @@ function receiveHandler(operation, channelName, channelAddress, isSpecV3) { next() } else { throw new Error(\`\${nValidated} of ${ operation.messages().length } message schemas matched when exactly 1 should match\`); - }` : `await validateMessage(message.payload,'${ channelAddress }','${ message.name() }','publish');`; + }` : `await validateMessage(message.payload,'${ channelAddress }','${ message.name() }','publish', ${messageRuntimeValidation});`; return ` ${operation.hasSummary() ? ` @@ -51,7 +51,7 @@ function receiveHandler(operation, channelName, channelAddress, isSpecV3) { `; } -function sendHandler(operation, channelName, channelAddress, isSpecV3) { +function sendHandler(operation, channelName, channelAddress, isSpecV3, messageRuntimeValidation) { if (!operation.isSend()) { return ''; } @@ -65,7 +65,7 @@ function sendHandler(operation, channelName, channelAddress, isSpecV3) { ${ operation.messages().all().map(message => `try { - nValidated = await validateMessage(message.payload,'${ channelAddress }','${ message.name() }','subscribe', nValidated); + nValidated = await validateMessage(message.payload,'${ channelAddress }','${ message.name() }','subscribe', nValidated, ${messageRuntimeValidation}); } catch { };`).join('\n') } @@ -74,7 +74,7 @@ function sendHandler(operation, channelName, channelAddress, isSpecV3) { next() } else { throw new Error(\`\${nValidated} of ${ operation.messages().length } message schemas matched when exactly 1 should match\`); - }` : `await validateMessage(message.payload,'${ channelAddress }','${ message.name() }','subscribe');`; + }` : `await validateMessage(message.payload,'${ channelAddress }','${ message.name() }','subscribe', ${messageRuntimeValidation});`; return ` ${operation.hasSummary() ? ` @@ -94,7 +94,7 @@ function sendHandler(operation, channelName, channelAddress, isSpecV3) { `; } -function routeCode(channel, isSpecV3) { +function routeCode(channel, isSpecV3, messageRuntimeValidation) { const channelName = channel.id(); const generalImport = ` const Router = require('hermesjs/lib/router'); @@ -110,20 +110,21 @@ function routeCode(channel, isSpecV3) { for (const operation of channel.operations()) { if (operation.isSend()) { - routeHandler += sendHandler(operation, channel.id(), channel.address(), isSpecV3); + routeHandler += sendHandler(operation, channel.id(), channel.address(), isSpecV3, messageRuntimeValidation); } if (operation.isReceive()) { - routeHandler += receiveHandler(operation, channel.id(), channel.address(), isSpecV3); + routeHandler += receiveHandler(operation, channel.id(), channel.address(), isSpecV3, messageRuntimeValidation); } } return {routeHandler}; } -export default function routeRender({asyncapi}) { +export default function routeRender({asyncapi, params}) { const majorSpecVersion = parseInt(asyncapi.version().split('.')[0], 10); const isSpecV3 = (majorSpecVersion === 3); + const messageRuntimeValidation = params.messageRuntimeValidation; return asyncapi.channels().all().map(channel => { - return routeCode(channel, isSpecV3); + return routeCode(channel, isSpecV3, messageRuntimeValidation); }); } \ No newline at end of file diff --git a/template/src/lib/message-validator.js b/template/src/lib/message-validator.js index 828b6be9..485e1bbc 100644 --- a/template/src/lib/message-validator.js +++ b/template/src/lib/message-validator.js @@ -16,7 +16,10 @@ function validateMessageIdentifiers(asyncApiSpec) { return missingNames; } -function performPreGenValidation(asyncApiFilePath) { +function performPreGenValidation(asyncApiFilePath, messageRuntimeValidation) { + if (messageRuntimeValidation === false) { + return; + } const fileContents = fs.readFileSync(asyncApiFilePath, 'utf8'); const asyncApiSpec = yaml.load(fileContents); @@ -24,20 +27,30 @@ function performPreGenValidation(asyncApiFilePath) { if (missingNames.length > 0) { const errorMessage = `msgIdentifier "name" does not exist for message(s): ${missingNames.join(', ')}`; - throw new Error(errorMessage); + const warningMessage = 'If you are not able to modify your AsyncAPI document to add missing message IDs, then disable runtime validation logic by passing parameter messageRuntimeValidation set to false'; + const error = new Error(errorMessage); + error.warning = warningMessage; + error.name = 'AsyncAPIValidationError'; + throw error; } } // Try to parse the payload, and increment nValidated if parsing was successful. -module.exports.validateMessage = async ( +async function validateMessage ( payload, channelName, messageName, operation, + messageRuntimeValidation, nValidated = 0 -) => { +) { + if (messageRuntimeValidation === false) { + return nValidated + 1; + } + + const asyncApiFilePath = path.resolve(__dirname, "../../asyncapi.yaml"); try { - const asyncApiFilePath = path.resolve(__dirname, "../../asyncapi.yaml"); + performPreGenValidation(asyncApiFilePath, messageRuntimeValidation); const va = await AsyncApiValidator.fromSource(asyncApiFilePath, { msgIdentifier: "name", }); @@ -50,3 +63,7 @@ module.exports.validateMessage = async ( throw error; } }; + +module.exports = { + validateMessage +}; \ No newline at end of file