diff --git a/template/README.md.js b/template/README.md.js index 28149c00..38d6f1e3 100644 --- a/template/README.md.js +++ b/template/README.md.js @@ -1,6 +1,21 @@ import { File } from '@asyncapi/generator-react-sdk'; export default function readmeFile({asyncapi, params}) { + const server = asyncapi.allServers().get(params.server); + const protocol = server.protocol(); + const security = server.security(); + + let hasSecuritySchemeX509 = false; + let securitySchemeType; + if (params.securityScheme && security && security.length > 0) { + const securityReq = security[0].all(); + if (securityReq && securityReq.length > 0) { + securitySchemeType = securityReq[0].scheme().type(); + } + } + + hasSecuritySchemeX509 = (params.securityScheme && (protocol === 'kafka' || protocol === 'kafka-secure') && securitySchemeType === 'X509'); + return {`# ${ asyncapi.info().title() } @@ -12,7 +27,7 @@ ${ asyncapi.info().description() || '' } \`\`\`sh npm i \`\`\` -${(params.securityScheme && (asyncapi.server(params.server).protocol() === 'kafka' || asyncapi.server(params.server).protocol() === 'kafka-secure') && asyncapi.components().securityScheme(params.securityScheme).type() === 'X509') ? '1. (Optional) For X509 security provide files with all data required to establish secure connection using certificates. Place files like `ca.pem`, `service.cert`, `service.key` in the root of the project or the location that you explicitly specified during generation.' : ''} +${ hasSecuritySchemeX509 ? '1. (Optional) For X509 security provide files with all data required to establish secure connection using certificates. Place files like `ca.pem`, `service.cert`, `service.key` in the root of the project or the location that you explicitly specified during generation.' : ''} ## Import and start diff --git a/template/src/api/handlers/handler.js b/template/src/api/handlers/handler.js index 6a2320e6..209dcb09 100644 --- a/template/src/api/handlers/handler.js +++ b/template/src/api/handlers/handler.js @@ -8,43 +8,41 @@ import { File } from '@asyncapi/generator-react-sdk'; const OPTIONS_MESSAGE_HEADERS_STRING = 'options.message.headers'; -function publishHandler(channel) { - if (!channel.hasPublish()) { +function receiveHandler(operation) { + if (!operation.isReceive()) { return ''; } - const lambdaChannel = channel.publish().ext('x-lambda'); - const publishOperationId = channel.publish().id(); - const publishMessage = channel.publish().message(0); + const operationId = operation.id(); + const message = operation.messages().all()[0]; + const lambdaChannel = operation.extensions().get('x-lambda'); const exportedHandler = ` /** - * Registers a middleware function for the ${publishOperationId} operation to be executed during request processing. + * Registers a middleware function for the ${operationId} operation to be executed during request processing. * * Middleware functions have access to options object that you can use to access the message content and other helper functions * * @param {function} middlewareFn - The middleware function to be registered. * @throws {TypeError} If middlewareFn is not a function. */ - handler.${convertOpertionIdToMiddlewareFn( - channel.publish().id() - )} = (middlewareFn) => { + handler.${convertOpertionIdToMiddlewareFn(operationId)} = (middlewareFn) => { if (typeof middlewareFn !== 'function') { throw new TypeError('middlewareFn must be a function'); } - ${publishOperationId}Middlewares.push(middlewareFn); + ${operationId}Middlewares.push(middlewareFn); } `; const privateHandlerLogic = ` /** - * ${channel.publish().summary() || ''} + * ${operation.hasSummary() ? operation.summary() : ''} * * @param {object} options * @param {object} options.message ${ - publishMessage.headers() - ? Object.entries(publishMessage.headers().properties()) + message.headers() + ? Object.entries(message.headers().properties()) .map(([fieldName, field]) => { return docline(field, fieldName, OPTIONS_MESSAGE_HEADERS_STRING); }) @@ -53,8 +51,8 @@ function publishHandler(channel) { } * ${ - publishMessage.payload() - ? Object.entries(publishMessage.payload().properties()) + message.payload() + ? Object.entries(message.payload().properties()) .map(([fieldName, field]) => { return docline(field, fieldName, OPTIONS_MESSAGE_HEADERS_STRING); }) @@ -62,7 +60,7 @@ function publishHandler(channel) { : '' } */ - handler._${publishOperationId} = async ({message}) => { + handler._${operationId} = async ({message}) => { ${ lambdaChannel ? ` @@ -74,7 +72,7 @@ function publishHandler(channel) { .then(res => res.json()) .then(json => console.log(json)) .catch(err => { throw err; });` - : `for (const middleware of ${publishOperationId}Middlewares) { + : `for (const middleware of ${operationId}Middlewares) { await middleware(message); }` } @@ -84,7 +82,7 @@ function publishHandler(channel) { return ` ${lambdaChannel ? 'const fetch = require("node-fetch");' : ''} - const ${publishOperationId}Middlewares = []; + const ${operationId}Middlewares = []; ${exportedHandler} @@ -92,42 +90,40 @@ function publishHandler(channel) { `; } -function subscribeHandler(channel) { - if (!channel.hasSubscribe()) { +function sendHandler(operation) { + if (!operation.isSend()) { return ''; } - const subscribeOperationId = channel.subscribe().id(); - const subscribeMessage = channel.subscribe().message(0); + const operationId = operation.id(); + const message = operation.messages().all()[0]; const exportedHandler = ` /** - * Registers a middleware function for the ${subscribeOperationId} operation to be executed during request processing. + * Registers a middleware function for the ${operationId} operation to be executed during request processing. * * Middleware functions have access to options object that you can use to access the message content and other helper functions * * @param {function} middlewareFn - The middleware function to be registered. * @throws {TypeError} If middlewareFn is not a function. */ - handler.${convertOpertionIdToMiddlewareFn( - channel.subscribe().id() - )} = (middlewareFn) => { + handler.${convertOpertionIdToMiddlewareFn(operationId)} = (middlewareFn) => { if (typeof middlewareFn !== 'function') { throw new TypeError('middlewareFn must be a function'); } - ${subscribeOperationId}Middlewares.push(middlewareFn); + ${operationId}Middlewares.push(middlewareFn); } `; const privateHandlerLogic = ` /** - * ${channel.subscribe().summary() || ''} + * ${operation.hasSummary() ? operation.summary() : ''} * * @param {object} options * @param {object} options.message ${ - subscribeMessage.headers() - ? Object.entries(subscribeMessage.headers().properties()) + message.headers() + ? Object.entries(message.headers().properties()) .map(([fieldName, field]) => { return docline(field, fieldName, OPTIONS_MESSAGE_HEADERS_STRING); }) @@ -136,8 +132,8 @@ function subscribeHandler(channel) { } * ${ - subscribeMessage.payload() - ? Object.entries(subscribeMessage.payload().properties()) + message.payload() + ? Object.entries(message.payload().properties()) .map(([fieldName, field]) => { return docline(field, fieldName, OPTIONS_MESSAGE_HEADERS_STRING); }) @@ -145,15 +141,15 @@ function subscribeHandler(channel) { : '' } */ - handler._${subscribeOperationId} = async ({message}) => { - for (const middleware of ${subscribeOperationId}Middlewares) { + handler._${operationId} = async ({message}) => { + for (const middleware of ${operationId}Middlewares) { await middleware(message); } }; `; return ` - const ${subscribeOperationId}Middlewares = []; + const ${operationId}Middlewares = []; ${exportedHandler} @@ -167,21 +163,22 @@ export default function handlerRender({ const general = ` const handler = module.exports = {}; `; - - const channels = asyncapi.channels(); - return Object.entries(channels).map(([channelName, channel]) => { - const hasPublish = channel.publish(); - const hasSubscribe = channel.hasSubscribe(); - - return ( - - {` - ${general} - ${hasPublish ? publishHandler(channel) : ''} - ${hasSubscribe ? subscribeHandler(channel) : ''} - `} - - ); + return asyncapi.channels().all().map(channel => { + const channelName = channel.id(); + + let routeHandler = ` + ${general} + `; + + for (let operation of channel.operations()) { + if (operation.isSend()) { + routeHandler += sendHandler(operation); + } + if (operation.isReceive()) { + routeHandler += receiveHandler(operation); + } + } + return {routeHandler}; }); } diff --git a/template/src/api/index.js b/template/src/api/index.js index 73b363cd..9df2b239 100644 --- a/template/src/api/index.js +++ b/template/src/api/index.js @@ -91,11 +91,12 @@ export default function indexEntrypointFile({asyncapi, params}) { const handlers = asyncapi.channels().all().map(channel => { const channelName = channel.id(); - return channel.operations().all().map(operation => { + const x = channel.operations().all().map(operation => { let operationId = operation.id(); return `${convertOpertionIdToMiddlewareFn(operationId)} : require('./handlers/${convertToFilename(channelName)}').${convertOpertionIdToMiddlewareFn(operationId)}` - }).join(','); - }).join('\n'); + }); + return x; + }).join(','); return {` diff --git a/template/src/api/routes/route.js b/template/src/api/routes/route.js index d34f3c31..e69675c2 100644 --- a/template/src/api/routes/route.js +++ b/template/src/api/routes/route.js @@ -2,23 +2,23 @@ import { File } from '@asyncapi/generator-react-sdk'; import { camelCase, convertToFilename, toHermesTopic } from '../../../../helpers/index'; -function publishHandler(channel, channelName) { - if (!channel.hasPublish()) { +function receiveHandler(operation, channelName) { + if (!operation.isReceive()) { return ''; } - const publishOperationId = channel.publish().id(); - const publishMessage = channel.publish().message(0); + const operationId = operation.id(); + const message = operation.messages().all()[0]; return ` - ${channel.publish().summary() ? ` + ${operation.hasSummary() ? ` /** - * ${ channel.publish().summary() } + * ${ operation.summary() } */ `: ''} router.use('${toHermesTopic(channelName)}', async (message, next) => { try { - ${channel.publish().hasMultipleMessages() + ${(operation.messages().length > 1) ? ` /* * TODO: If https://github.com/asyncapi/parser-js/issues/372 is addressed, simplify this @@ -31,21 +31,21 @@ function publishHandler(channel, channelName) { // Validate payload against each message and count those which validate ${ - Array.from(Array(channel.publish().messages().length).keys()).map(i => `try { - nValidated = await validateMessage(message.payload,'${ channelName }','${ channel.publish().message(i).name() }','publish', nValidated); + operation.messages().all().map(message => `try { + nValidated = await validateMessage(message.payload,'${ channelName }','${ message.name() }','publish', nValidated); } catch { };`).join('\n') } if (nValidated === 1) { - await ${camelCase(channelName)}Handler._${publishOperationId}({message}); + await ${camelCase(channelName)}Handler._${operationId}({message}); next() } else { - throw new Error(\`\${nValidated} of ${ channel.publish().messages().length } message schemas matched when exactly 1 should match\`); + throw new Error(\`\${nValidated} of ${ operation.messages().length } message schemas matched when exactly 1 should match\`); } ` : ` - await validateMessage(message.payload,'${ channelName }','${ publishMessage.name() }','publish'); - await ${camelCase(channelName)}Handler._${ publishOperationId }({message}); + await validateMessage(message.payload,'${ channelName }','${ message.name() }','publish'); + await ${camelCase(channelName)}Handler._${ operationId }({message}); next(); ` } @@ -56,44 +56,44 @@ function publishHandler(channel, channelName) { `; } -function subscribeHandler(channel, channelName) { - if (!channel.hasSubscribe()) { +function sendHandler(operation, channelName) { + if (!operation.isSend()) { return ''; } - const subscribeOperationId = channel.subscribe().id(); - const subscribeMessage = channel.subscribe().message(0); + const operationId = operation.id(); + const message = operation.messages().all()[0]; return ` - ${channel.subscribe().summary() ? ` + ${operation.hasSummary() ? ` /** - * ${ channel.subscribe().summary() } + * ${ operation.summary() } */ `: ''} router.use('${toHermesTopic(channelName)}', async (message, next) => { try { - ${channel.subscribe().hasMultipleMessages() + ${(operation.messages().length > 1) ? ` let nValidated = 0; // For oneOf, only one message schema should match. // Validate payload against each message and count those which validate ${ - Array.from(Array(channel.subscribe().messages().length).keys()).map(i => `try { - nValidated = await validateMessage(message.payload,'${ channelName }','${ channel.subscribe().message(i).name() }','subscribe', nValidated); + operation.messages().all().map(message => `try { + nValidated = await validateMessage(message.payload,'${ channelName }','${ operation.message(i).name() }','subscribe', nValidated); } catch { };`).join('\n') } if (nValidated === 1) { - await ${camelCase(channelName)}Handler._${subscribeOperationId}({message}); + await ${camelCase(channelName)}Handler._${operationId}({message}); next() } else { - throw new Error(\`\${nValidated} of ${ channel.subscribe().messages().length } message schemas matched when exactly 1 should match\`); + throw new Error(\`\${nValidated} of ${ operation.messages().length } message schemas matched when exactly 1 should match\`); } ` : ` - await validateMessage(message.payload,'${ channelName }','${ subscribeMessage.name() }','subscribe'); - await ${camelCase(channelName)}Handler._${ subscribeOperationId }({message}); + await validateMessage(message.payload,'${ channelName }','${ message.name() }','subscribe'); + await ${camelCase(channelName)}Handler._${ operationId }({message}); next(); ` } @@ -104,10 +104,8 @@ function subscribeHandler(channel, channelName) { `; } -function routeCode(channel, channelName) { - const hasPublish = channel.publish(); - const hasSubscribe = channel.hasSubscribe(); - +function routeCode(channel) { + const channelName = channel.id(); const generalImport = ` const Router = require('hermesjs/lib/router'); const { validateMessage } = require('../../lib/message-validator'); @@ -116,21 +114,24 @@ function routeCode(channel, channelName) { module.exports = router; `; - return ( - - {` - ${generalImport} - ${hasPublish ? publishHandler(channel, channelName): ''} - ${hasSubscribe ? subscribeHandler(channel, channelName): ''} - `} - - ); + let routeHandler = ` + ${generalImport} + `; + + for (let operation of channel.operations()) { + if (operation.isSend()) { + routeHandler += sendHandler(operation, channel.id()); + } + if (operation.isReceive()) { + routeHandler += receiveHandler(operation, channel.id()); + } + } + + return {routeHandler}; } export default function routeRender({asyncapi}) { - const channels = asyncapi.channels(); - - return Object.entries(channels).map(([channelName, channel]) => { - return routeCode(channel, channelName); + return asyncapi.channels().all().map(channel => { + return routeCode(channel); }); } \ No newline at end of file