Skip to content

Commit

Permalink
added the message validation parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
ibishal committed Jul 1, 2024
1 parent 8877f89 commit b5bea3f
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 17 deletions.
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
Expand Down
5 changes: 4 additions & 1 deletion template/src/api/middlewares/error-logger.js
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
23 changes: 12 additions & 11 deletions template/src/api/routes/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 '';
}
Expand All @@ -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')
}
Expand All @@ -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() ? `
Expand All @@ -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 '';
}
Expand All @@ -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')
}
Expand All @@ -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() ? `
Expand All @@ -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');
Expand All @@ -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 <File name={`${convertToFilename(channelName)}.js`}>{routeHandler}</File>;
}

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);
});
}
27 changes: 22 additions & 5 deletions template/src/lib/message-validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,41 @@ 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);

const missingNames = validateMessageIdentifiers(asyncApiSpec);

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",
});
Expand All @@ -50,3 +63,7 @@ module.exports.validateMessage = async (
throw error;
}
};

module.exports = {
validateMessage
};

0 comments on commit b5bea3f

Please sign in to comment.