Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: support asyncapi v3 #294

Merged
merged 31 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
c5db980
update packages to support v3
kaushik-rishi Apr 29, 2024
038d50f
rewrite package.json.js
kaushik-rishi Apr 29, 2024
92ca38b
rewrite common.yml.js
kaushik-rishi Apr 29, 2024
20691d6
rewrite entrypoint file
kaushik-rishi Apr 30, 2024
0c1a899
rewrite entrypoint file
kaushik-rishi Apr 30, 2024
dd4bbd5
rewrite handlers, readme, routes
kaushik-rishi Apr 30, 2024
80c1cf1
convert serverVariables to map
kaushik-rishi Apr 30, 2024
27eea8b
update snapshot tests - 1
kaushik-rishi Apr 30, 2024
8bc93ab
update snapshot tests - 2
kaushik-rishi Apr 30, 2024
78f4e44
fix linting
kaushik-rishi Apr 30, 2024
afb5e63
reduce duplicacy in handler
kaushik-rishi Apr 30, 2024
2d2b4f5
Merge branch 'master' into migrate-v3
kaushik-rishi Apr 30, 2024
0317007
remove intermediary variables
kaushik-rishi Apr 30, 2024
b31bb29
re-add test command
kaushik-rishi Apr 30, 2024
d5242f5
formatting issues
kaushik-rishi Apr 30, 2024
f370bec
add mocks for spec v3 version
kaushik-rishi Apr 30, 2024
e6f5fdc
add new snapshot tests
kaushik-rishi Apr 30, 2024
c32123c
update snapshot tests
kaushik-rishi Apr 30, 2024
3f1e6a7
update snapshot tests - kafka v3
kaushik-rishi Apr 30, 2024
ddc2d2f
update package.json
kaushik-rishi May 1, 2024
5327cf1
add linter ignores for integration.test.js
kaushik-rishi May 1, 2024
1f0370c
uncomment and enable security checks
kaushik-rishi May 1, 2024
88a8c66
readme v3 changes
kaushik-rishi May 1, 2024
0d953a8
disable validation for spec v3 and test pub-sub
kaushik-rishi May 4, 2024
2f60498
update snapshot tests - bug fixes
kaushik-rishi May 4, 2024
1c40743
update linting
kaushik-rishi May 4, 2024
c7914d5
disable validation package installation for v3
kaushik-rishi May 4, 2024
fef4790
disable validation package installation - update snapshots
kaushik-rishi May 4, 2024
0f0161c
Merge branch 'master' into migrate-v3
derberg May 6, 2024
53ad16c
disable validation module import in spec v3
kaushik-rishi May 6, 2024
b780a68
fix linting
kaushik-rishi May 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .sonarcloud.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sonar.exclusions=test/integration.test.js
9 changes: 2 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ $ npm install -g @asyncapi/cli

# Run generation from the root of the template to use tes MQTT example
# To use the template
$ asyncapi generate fromTemplate test/mocks/mqtt/asyncapi.yml @asyncapi/nodejs-template -o test/output -p server=production
$ asyncapi generate fromTemplate test/mocks/mqtt/asyncapi-v3.yml @asyncapi/nodejs-template -o test/output -p server=production

# OR

# To test your local changes provided inside template
$ asyncapi generate fromTemplate test/mocks/mqtt/asyncapi.yml ./ -o test/output -p server=production
$ asyncapi generate fromTemplate test/mocks/mqtt/asyncapi-v3.yml ./ -o test/output -p server=production

##
## Install dependencies of generated library
Expand Down Expand Up @@ -100,10 +100,6 @@ $ npm run test:example
$ npm install mqtt -g

#You should see the sent message in the logs of the started example.
#Notice that the server automatically validates incoming messages and logs out validation errors

#publish an invalid message.
$ mqtt pub -t 'smartylighting/streetlights/1/0/event/123/lighting/measured' -h 'test.mosquitto.org' -m '{"id": 1, "lumens": "3", "sentAt": "2017-06-07T12:34:32.000Z"}'

#publish a valid message
$ mqtt pub -t 'smartylighting/streetlights/1/0/event/123/lighting/measured' -h 'test.mosquitto.org' -m '{"id": 1, "lumens": 3, "sentAt": "2017-06-07T12:34:32.000Z"}'
Expand All @@ -123,7 +119,6 @@ To avoid this, user code remains external to the generated code, functioning as
Facilitating this separation involves creating handlers and associating them with their respective routes. These handlers can then be seamlessly integrated into the template's workflow by importing the appropriate methods to register the handlers. In doing so, the template's `client.register<operationId>Middleware` method becomes the bridge between the user-written handlers and the generated code. This can be used to register middlewares for specific methods on specific channels.

Look closely into [example script](test/example/script.js) that works with library generated using [this MQTT based AsyncAPI document](test/mocks/mqtt/asyncapi.yml). Look at available handlers API for reading incomming messages and processing outgoing messages. Learn how to start generated server with `init()` and also learn how to send messages, if needed.
```

## Template configuration

Expand Down
10 changes: 3 additions & 7 deletions helpers/channels-topics.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,8 @@ export function toHermesTopic(str) {
return str.replace(/\{([^}]+)\}/g, ':$1');
}

export function channelNamesWithPublish(asyncapi) {
const result = [];
asyncapi.channelNames().forEach((name) => {
if (asyncapi.channel(name).hasPublish()) result.push(name);
});
return result;
export function channelNamesWithReceive(asyncapi) {
return asyncapi.channels().filterByReceive().map(channel => channel.address());
}

export function host(url) {
Expand Down Expand Up @@ -151,4 +147,4 @@ export function getProtocol(p) {
// https://mozilla.github.io/nunjucks/templating.html#dump
export function dump(obj) {
return JSON.stringify(obj);
}
}
462 changes: 244 additions & 218 deletions package-lock.json

Large diffs are not rendered by default.

15 changes: 8 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,22 @@
"@asyncapi/generator-hooks": "^0.1.0",
"@asyncapi/generator-react-sdk": "^1.0.18",
"eslint-plugin-react": "^7.34.1",
"filenamify": "^4.1.0",
"filenamify": "^4.3.0",
"js-beautify": "^1.15.1",
"lodash": "^4.17.15",
"lodash": "^4.17.21",
"markdown-toc": "^1.2.0"
},
"devDependencies": {
"@asyncapi/generator": "^1.17.25",
"eslint": "^8.7.0",
"eslint": "^8.57.0",
"eslint-plugin-jest": "^25.7.0",
"eslint-plugin-sonarjs": "^0.11.0",
"jest": "^27.3.1",
"node-fetch": "^2.6.1",
"rimraf": "^5.0.1"
"jest": "^27.5.1",
"node-fetch": "^2.7.0",
"rimraf": "^5.0.5"
},
"generator": {
"apiVersion": "v3",
"supportedProtocols": [
"amqp",
"mqtt",
Expand Down Expand Up @@ -94,4 +95,4 @@
"^nimma/(.*)": "<rootDir>/node_modules/nimma/dist/cjs/$1"
}
}
}
}
17 changes: 16 additions & 1 deletion template/README.md.js
Original file line number Diff line number Diff line change
@@ -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 <File name={'README.md'}>
{`# ${ asyncapi.info().title() }

Expand All @@ -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

Expand Down
27 changes: 17 additions & 10 deletions template/config/common.yml.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { File } from '@asyncapi/generator-react-sdk';
import { camelCase, channelNamesWithPublish, dump, host, port, queueName, stripProtocol, toAmqpTopic, toKafkaTopic, toMqttTopic } from '../../helpers/index';
import { camelCase, channelNamesWithReceive, dump, host, port, queueName, stripProtocol, toAmqpTopic, toKafkaTopic, toMqttTopic } from '../../helpers/index';
import { replaceServerVariablesWithValues } from '@asyncapi/generator-filters/src/customFilters';

export default function CommonConfigYAMLRender({ asyncapi, params }) {
const serverProtocol = asyncapi.server(params.server).protocol();
const serverVariables = asyncapi.server(params.server).variables();
const resolvedBrokerUrlWithReplacedVariables = replaceServerVariablesWithValues(asyncapi.server(params.server).url(), serverVariables);
const server = asyncapi.allServers().get(params.server);
const serverProtocol = server.protocol();
const serverVariablesArray = server.variables();
const serverVariables = {};
serverVariablesArray.forEach(item => {
serverVariables[item.id()] = item;
});

const resolvedBrokerUrlWithReplacedVariables = replaceServerVariablesWithValues(server.url(), serverVariables);

return (
<File name={'common.yml'}>
Expand Down Expand Up @@ -47,7 +53,7 @@ function amqpBlock(url, asyncapi) {
password:
host: ${host(url)}
port:
topics: ${dump(toAmqpTopic(channelNamesWithPublish(asyncapi)))}
topics: ${dump(toAmqpTopic(channelNamesWithReceive(asyncapi)))}
queue: ${queueName(asyncapi.info().title(), asyncapi.info().version())}
queueOptions:
exclusive: false
Expand All @@ -57,9 +63,10 @@ function amqpBlock(url, asyncapi) {
}

function mqttBlock(url, asyncapi, params) {
const server = asyncapi.allServers().get(params.server);
return ` mqtt:
url: ${asyncapi.server(params.server).protocol()}://${stripProtocol(url)}
topics: ${dump(toMqttTopic(channelNamesWithPublish(asyncapi)))}
url: ${server.protocol()}://${stripProtocol(url)}
topics: ${dump(toMqttTopic(channelNamesWithReceive(asyncapi)))}
qos:
protocol: mqtt
retain:
Expand All @@ -75,7 +82,7 @@ function kafkaBlock(url, asyncapi) {
consumerOptions:
groupId: ${camelCase(asyncapi.info().title())}
topics:
${channelNamesWithPublish(asyncapi).map(topic => `- ${toKafkaTopic(topic)}`).join('\n')}
${channelNamesWithReceive(asyncapi).map(topic => `- ${toKafkaTopic(topic)}`).join('\n')}
topicSeparator: '__'
topicPrefix:
`;
Expand All @@ -87,12 +94,12 @@ function kafkaProductionBlock(params, asyncapi) {
ssl:
rejectUnauthorized: true
`;
if (params.securityScheme && asyncapi.components().securityScheme(params.securityScheme).type() !== 'X509') {
if (params.securityScheme && asyncapi.components().securitySchemes().get(params.securityScheme).type() !== 'X509') {
productionBlock += ` sasl:
mechanism: 'plain'
username:
password:
`;
}
return productionBlock;
}
}
9 changes: 7 additions & 2 deletions template/package.json.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@ export default function packageFile({ asyncapi, params }) {
dotenv: '8.1.0',
hermesjs: '2.x',
'hermesjs-router': '1.x',
'asyncapi-validator': '3.0.0',
'node-fetch': '2.6.0',
'node-yaml-config': '0.0.4',
};

const serverProtocol = asyncapi.server(params.server).protocol();
const majorSpecVersion = parseInt(asyncapi.version().split('.')[0], 10);
const isSpecV3 = (majorSpecVersion === 3);
if (!isSpecV3) {
dependencies['asyncapi-validator'] = '3.0.0';
}

const serverProtocol = asyncapi.allServers().get(params.server).protocol();
if (serverProtocol === 'mqtt' || serverProtocol === 'mqtts') {
dependencies['hermesjs-mqtt'] = '2.x';
} else if (serverProtocol === 'kafka' || serverProtocol === 'kafka-secure') {
Expand Down
Loading
Loading