Skip to content

Commit

Permalink
some readme and examples improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
derberg committed Dec 16, 2024
1 parent f7f6ceb commit f38413e
Show file tree
Hide file tree
Showing 17 changed files with 5,508 additions and 1,313 deletions.
32 changes: 32 additions & 0 deletions packages/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# ⚠️ **EXPERIMENTAL FEATURE WARNING** ⚠️

> **Warning:** The following feature is **experimental** and may change without notice. Use at your own risk. This feature is not guaranteed to be stable and should not be used in production environments.

## Overview

This approach with templates developed as part of `generator` repository is a work in progress. This was started because of the following issues:
- [How about a monorepo](https://github.com/asyncapi/generator/issues/1044)
- [Put all (most) templates into the generator together for better developers' experience](https://github.com/asyncapi/generator/issues/1249)
- [Proof of concept of templates as part of generator monorepo](https://github.com/asyncapi/generator/issues/1269)

## Assumptions and Principles

1. When developing templates further, follow the nested folder structure where templates are group by their usage purpose.
2. Idea is that templates inside generator are grouped under a predefined opinionated types, like `client, sdk, docs, scripts`. This is a subject to change over time the development proceeds and we check these types in action:
- `client` purpose is that the template generates a client library that anyone can easily import and use in their server to interact with the API. In theory, this could also be a client used to develop a server, thus no dedicated `server` type
- `sdk` assumption is that people might need a more sophisticated project generation than simple client. Template do generate `sdk` should ideally extend existing `client`
- `docs` is for templates that we already have but outside this repo, html or markdown generation, but might be more standards
- `scripts` is rough idea to address idea that we can just generate script that one can use to setup topics in a broker
3. `components` package should contain a set of reusable react components that could be shared between templates
4. `helpers` package should contain a set of reusable helpers. They would focus mainly on smart extract of info from AsyncAPI document using Parser API. Templates should avoid using AsyncAPI Parser API directly, but through well tested `helpers`
5. Each new template or new feature in existing template must be done with reusability in mind. Custom helpers and components should be limited to minimum
6. Helpers need dedicated tests. Still to agree if we should base these on dummy AsyncAPI documents or just mock fake Parser objects inside tests.
7. Components should also be tested separately, expecially if they are reused across templates
8. Each template should have a set of snapshot tests that help understand if changes in the PR affect the output of the template
9. Every time new template feature is added it must be consulted with:
- Spec reference docs using [raw docs](https://www.asyncapi.com/docs/reference/specification/v3.0.0) or [visualizer](https://www.asyncapi.com/docs/reference/specification/v3.0.0-explorer)
- [Parser API](https://github.com/asyncapi/parser-api/blob/master/docs/api.md) to use it's capabilities instead of doing workarounds like for example `binding.json()["query"]["properties"]`

//TODO: we still need to figure out how not only test output changes but also if the output will work with real service: contract testing with mocks. To evaluate Microcks and Specmatic

4 changes: 3 additions & 1 deletion packages/templates/clients/js/websocket/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ You can test this template:
1. Clone the project and run `npm install`
2. Navigate to `packages/templates/clients/js/websocket`
3. Install with `npm install` and run test with `npm run test`
4. Start example script that uses a client library generated by the test: `node example.js`
4. Start example script that uses a client library generated by the test: `node example.js`

> By default this is testing against Postman echo service. You can modify `packages/templates/clients/js/websocket/example.js` and change first line to `const WSClient = require('./tests/temp/snapshotTestResult/client-hoppscotch.js');` and run `node example.js` again. You will see example still works but agains different API. This is possible as both AsyncAPI documents have the same name of operation for sending messages: `sendEchoMessage` so each client generated has the same API.
56 changes: 50 additions & 6 deletions packages/templates/clients/js/websocket/__transpiled/client.js.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Large diffs are not rendered by default.

17 changes: 13 additions & 4 deletions packages/templates/clients/js/websocket/example.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
const WSClient = require('./tests/temp/snapshotTestResult/client.js');
const WSClient = require('./tests/temp/snapshotTestResult/client-postman.js');
// Example usage
const wsClient = new WSClient();

// Example of how custom message handler that operates on incoming messages can look like
function myHandler(message) {
console.log('====================');
console.log('Just proving I got the message in myHandler:', message);
console.log('====================');
}

// Example of custom error handler
function myErrorHandler(error) {
console.error('Errors from Websocket:', error.message);
}

async function main() {
// Connect to WebSocket
wsClient.registerMessageHandler(myHandler);
wsClient.registerErrorHandler(myErrorHandler);

try {
await wsClient.connect();
await wsClient.registerMessageHandler(myHandler);

// Loop to send messages every 5 seconds
const interval = 5000; // 5 seconds
Expand All @@ -26,7 +35,7 @@ async function main() {
await new Promise(resolve => setTimeout(resolve, interval));
}
} catch (error) {
console.error('Failed to connect to WebSocket:', error);
console.error('Failed to connect to WebSocket:', error.message);
}
}

Expand Down
27 changes: 27 additions & 0 deletions packages/templates/clients/js/websocket/helpers/servers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Get server URL from AsyncAPI server object.
*
* @param {object} server - The AsyncAPI server object.
*
* return {string} - The server URL.
*/
function getServerUrl(server) {
let url = server.host();

//might be that somebody by mistake duplicated protocol info inside the host field
//we need to make sure host do not hold protocol info
if (server.protocol() && !url.includes(server.protocol())) {
url = `${server.protocol()}://${url}`;
}

if (server.hasPathname()) {
url = `${url}${server.pathname()}`;
}

return url;
}

//TODO: this separate file for helpers for servers represents approach to keep all helpers in separate files related to extractions of data from specific high level AsyncAPI objects. Here we will have more helpers for example related to variables extraction from servers, security, etc.

export { getServerUrl };

4 changes: 3 additions & 1 deletion packages/templates/clients/js/websocket/helpers/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
* Get client name from AsyncAPI info.title
*
* @param {object} info - The AsyncAPI info object.
*
* return {string} - The client name with "Client" appended at the end.
*/
function getClientName(info) {
const title = info.title();
Expand All @@ -11,6 +13,6 @@ function getClientName(info) {
.replace(/^./, char => char.toUpperCase()) // Make the first letter uppercase
}Client`;
};

export { getClientName };

Loading

0 comments on commit f38413e

Please sign in to comment.