diff --git a/components/Asyncapi.js b/components/Asyncapi.js index d043c4aed..004ed9b6a 100644 --- a/components/Asyncapi.js +++ b/components/Asyncapi.js @@ -6,13 +6,11 @@ import { TableOfContents } from './TableOfContents'; // eslint-disable-next-line no-unused-vars import { AsyncAPIDocumentInterface } from '@asyncapi/parser'; -import { Operationsv3 } from './Operationsv3'; /** * @param {{asyncapi: AsyncAPIDocumentInterface, params: any}} param0 */ export function Asyncapi({ asyncapi, params }) { - const isV3 = asyncapi.version().split('.')[0] === '3'; return ( <> {params.frontMatter && } @@ -20,11 +18,7 @@ export function Asyncapi({ asyncapi, params }) { {params.toc !== 'false' && } - { - isV3 ? - : - - } + ); } diff --git a/components/Operations.js b/components/Operations.js index 8af591b08..baf2add56 100644 --- a/components/Operations.js +++ b/components/Operations.js @@ -12,6 +12,10 @@ import { FormatHelpers } from '../helpers/format'; // eslint-disable-next-line no-unused-vars import { AsyncAPIDocumentInterface, OperationInterface, ChannelInterface } from '@asyncapi/parser'; +function isV3({asyncapi}) { + return asyncapi.version().split('.')[0] === '3'; +} + /** * @param {{asyncapi: AsyncAPIDocumentInterface}} param0 */ @@ -31,13 +35,13 @@ export function Operations({ asyncapi }) { if (operation.reply() !== undefined) { type = 'request'; } else { - type = 'publish'; + type = 'send'; } } else if (operation.isReceive()) { if (operation.reply() !== undefined) { type = 'reply'; } else { - type = 'subscribe'; + type = 'receive'; } } operationsList.push( @@ -62,7 +66,31 @@ export function Operations({ asyncapi }) { ); } - +function getRenderedTypeForOperation({asyncapi, type}) { + const isv3 = isV3({asyncapi}); + if (isv3) { + switch (type) { + case 'request': + return 'REQUEST'; + case 'send': + return 'SEND'; + case 'reply': + return 'REPLY'; + case 'receive': + return 'RECEIVE'; + } + } + // For v2, we render the application view still + // Meaning the when you use publish operation it means other publish to your application because your application is subscribing to it. + switch (type) { + case 'send': // This is the publish operation + return 'SUB'; + case 'receive': // This is the subscribe operation + return 'PUB'; + } + // This case should never happen, if it does this function needs to be changed + return 'UNKNOWN'; +} /** * @param {{asyncapi: AsyncAPIDocumentInterface, type: string, operation: OperationInterface, channelName: string, channel: ChannelInterface}} param0 */ @@ -76,15 +104,8 @@ function Operation({ asyncapi, type, operation, channelName, channel }) { // NOS const applyToAllServers = asyncapi.servers().all().length === channel.servers().all().length; const servers = applyToAllServers ? [] : channel.servers().all(); const security = operation.security(); - let renderedType; - switch (type) { - case 'publish': - renderedType = 'PUB'; - break; - case 'subscribe': - renderedType = 'SUB'; - break; - } + const renderedType = getRenderedTypeForOperation({asyncapi, type}); + const showInfoList = operationId || (servers && servers.length); return ( @@ -95,7 +116,7 @@ function Operation({ asyncapi, type, operation, channelName, channel }) { // NOS {operation.summary() && ( - *{operation.summary()}* + *{operation.summary().trim()}* )} @@ -154,10 +175,13 @@ function Operation({ asyncapi, type, operation, channelName, channel }) { // NOS - + + + ); } + /** * @param {{channel: ChannelInterface}} param0 */ @@ -174,20 +198,36 @@ function OperationParameters({ channel }) { ); } +function getOperationMessageText({asyncapi, type}) { + let messagesText = 'Accepts **one of** the following messages:'; + if (isV3({asyncapi})) { + if (type === 'send') { + messagesText = 'Sending **one of** the following messages:'; + } else if (type === 'request') { + messagesText = 'Request contains **one of** the following messages:'; + } else if (type === 'receive') { + messagesText = 'Receive **one of** the following messages:'; + } else if (type === 'reply') { + messagesText = 'Request contains **one of** the following messages:'; + } + } + return messagesText; +} /** - * @param {{operation: OperationInterface}} param0 + * @param {{operation: OperationInterface, asyncapi: AsyncAPIDocumentInterface, type: string}} param0 */ -function OperationMessages({ operation }) { +function OperationMessages({ asyncapi, operation, type }) { const messages = operation.messages().all(); if (messages.length === 0) { return null; } + const messageText = getOperationMessageText({asyncapi, type}); return ( <> {messages.length > 1 && ( - Accepts **one of** the following messages: + {messageText} )} {messages.map((msg, idx) => ( @@ -196,3 +236,81 @@ function OperationMessages({ operation }) { ); } + +/** + * @param {{operation: OperationInterface}} param0 + */ +function OperationReply({ operation, type }) { + const reply = operation.reply(); + if (reply === undefined) { + return null; + } + const explicitChannel = reply.channel(); + + let typeText; + if (operation.isSend()) { + typeText = 'Request'; + } else if (operation.isReceive()) { + typeText = 'Response'; + } + + let messagesText; + if (type === 'request') { + messagesText = 'Receive **one of** the following messages as a response to the request:'; + } else if (type === 'reply') { + messagesText = 'Replying with **one of** the following messages:'; + } + + return ( + +
+ {`${typeText} information`} +
+ + {explicitChannel && {type} should be done to channel: `{explicitChannel.address()}`} + + + + <> + {reply.messages().length > 1 && ( + + {messagesText} + + )} + {reply.messages().length > 1 && reply.messages().map((msg, idx) => ( + + ))} + + +
+ ); +} + +/** + * @param {{reply: OperationReplyInterface}} param0 + */ +function OperationReplyAddress({ reply }) { + const address = reply.address(); + if (address === undefined) { + return null; + } + const location = address.location(); + + return ( + +
+ {'Operation reply address information'} +
+ + {address.hasDescription() && ( + + {address.description()} + + )} + + Operation reply address location: `{location}` + + +
+ ); +} diff --git a/components/Operationsv3.js b/components/Operationsv3.js deleted file mode 100644 index 3a11f350b..000000000 --- a/components/Operationsv3.js +++ /dev/null @@ -1,295 +0,0 @@ -import { Text } from '@asyncapi/generator-react-sdk'; -import { Bindings } from './Bindings'; -import { Extensions } from './Extensions'; -import { Message } from './Message'; -import { Schema } from './Schema'; -import { Security } from './Security'; -import { Tags } from './Tags'; -import { Header, ListItem, Link } from './common'; -import { SchemaHelpers } from '../helpers/schema'; -import { FormatHelpers } from '../helpers/format'; - -// eslint-disable-next-line no-unused-vars -import { AsyncAPIDocumentInterface, OperationInterface, OperationReplyInterface, ChannelInterface } from '@asyncapi/parser'; - -/** - * @param {{asyncapi: AsyncAPIDocumentInterface}} param0 - */ -export function Operationsv3({ asyncapi }) { - const channels = asyncapi.channels(); - if (channels.isEmpty()) { - return null; - } - - const operationsList = []; - for (const channel of channels.all()) { - const channelName = channel.address(); - const operations = channel.operations().all(); - operations.map(operation => { - let type; - if (operation.isSend()) { - if (operation.reply() !== undefined) { - type = 'request'; - } else { - type = 'send'; - } - } else if (operation.isReceive()) { - if (operation.reply() !== undefined) { - type = 'reply'; - } else { - type = 'receive'; - } - } - operationsList.push( - - ); - }); - } - - return ( - <> -
- Operations -
- {operationsList} - - ); -} - -/** - * @param {{asyncapi: AsyncAPIDocumentInterface, type: string, operation: OperationInterface, channelName: string, channel: ChannelInterface}} param0 - */ -function Operation({ asyncapi, type, operation, channelName, channel }) { // NOSONAR - if (!operation || !channel) { - return null; - } - - const operationId = operation.operationId(); - const externalDocs = operation.externalDocs(); - const applyToAllServers = asyncapi.servers().all().length === channel.servers().all().length; - const servers = applyToAllServers ? [] : channel.servers().all(); - const security = operation.security(); - let renderedType; - switch (type) { - case 'request': - renderedType = 'REQUEST'; - break; - case 'send': - renderedType = 'SEND'; - break; - case 'reply': - renderedType = 'REPLY'; - break; - case 'receive': - renderedType = 'RECEIVE'; - break; - } - const showInfoList = operationId || (servers?.length); - - return ( - -
- {`${renderedType} \`${channelName}\` Operation`} -
- - {operation.summary() && ( - - *{operation.summary().trim()}* - - )} - - {showInfoList ? ( - - {operationId && Operation ID: `{operationId}`} - {servers && servers.length && ( - - Available only on servers:{' '} - {servers.map(s => { - const serverId = s.id(); - const slug = FormatHelpers.slugify(serverId); - return `[${serverId}](#${slug}-server)`; - }).join(', ')} - - )} - - ) : null} - - {channel.hasDescription() && ( - - {channel.description()} - - )} - {operation.hasDescription() && ( - - {operation.description()} - - )} - - {externalDocs && ( - - - {externalDocs.description() || 'Find more info here.'} - - - )} - - - - - - - - - - - - - - - - -
- ); -} -/** - * @param {{channel: ChannelInterface}} param0 - */ -function OperationParameters({ channel }) { - const parameters = SchemaHelpers.parametersToSchema(channel.parameters().all()); - if (!parameters) { - return null; - } - - return ( - -
Parameters
- -
- ); -} -/** - * @param {{operation: OperationInterface}} param0 - */ -function OperationMessages({ operation, type }) { - const messages = operation.messages().all(); - if (messages.length === 0) { - return null; - } - - let messagesText = 'Accepts **one of** the following messages:'; - if (type === 'send') { - messagesText = 'Sending **one of** the following messages:'; - } else if (type === 'request') { - messagesText = 'Request contains **one of** the following messages:'; - } else if (type === 'receive') { - messagesText = 'Receive **one of** the following messages:'; - } else if (type === 'reply') { - messagesText = 'Request contains **one of** the following messages:'; - } - - return ( - <> - {messages.length > 1 && ( - - {messagesText} - - )} - {messages.map((msg, idx) => ( - - ))} - - ); -} - -/** - * @param {{operation: OperationInterface}} param0 - */ -function OperationReply({ operation, type }) { - const reply = operation.reply(); - if (reply === undefined) { - return null; - } - const explicitChannel = reply.channel(); - - let typeText; - if (operation.isSend()) { - typeText = 'Request'; - } else if (operation.isReceive()) { - typeText = 'Response'; - } - - let messagesText = 'Accepts **one of** the following messages:'; - if (type === 'request') { - messagesText = 'Receive **one of** the following messages as a response to the request:'; - } else if (type === 'reply') { - messagesText = 'Replying with **one of** the following messages:'; - } - - return ( - -
- {`${typeText} information`} -
- - {explicitChannel && {type} should be done to channel: `{explicitChannel.address()}`} - - - - <> - {reply.messages().length > 1 && ( - - {messagesText} - - )} - {reply.messages().length > 1 && reply.messages().map((msg, idx) => ( - - ))} - - -
- ); -} - -/** - * @param {{reply: OperationReplyInterface}} param0 - */ -function OperationReplyAddress({ reply }) { - const address = reply.address(); - if (address === undefined) { - return null; - } - const location = address.location(); - - return ( - -
- {'Operation reply address information'} -
- - {address.hasDescription() && ( - - {address.description()} - - )} - - Operation reply address location: `{location}` - - -
- ); -} diff --git a/helpers/schema.js b/helpers/schema.js index f30d702a2..190df43a5 100644 --- a/helpers/schema.js +++ b/helpers/schema.js @@ -194,6 +194,11 @@ export class SchemaHelpers { return JSON.stringify(value); } + /** + * + * @param {import('@asyncapi/parser').ChannelParametersInterface} parameters + * @returns + */ static parametersToSchema(parameters) { if (parameters.length === 0) { return; @@ -204,7 +209,7 @@ export class SchemaHelpers { properties: parameters.reduce( (obj, parameter) => { const parameterName = parameter.id(); - obj[String(parameterName)] = Object.assign({}, parameter.schema().json()); + obj[String(parameterName)] = Object.assign({}, parameter.schema() === undefined ? {type: 'string'} : parameter.schema().json()); obj[String(parameterName)].description = parameter.description() || obj[String(parameterName)].description; obj[String(parameterName)][this.extParameterLocation] = parameter.location(); diff --git a/package-lock.json b/package-lock.json index b53ccd5a7..450479c2b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ }, "devDependencies": { "@asyncapi/cli": "^0.58.5", - "@asyncapi/parser": "^3.0.0-next-major-spec.2", + "@asyncapi/parser": "^3.0.0-next-major-spec.3", "@babel/preset-env": "^7.15.8", "@babel/preset-react": "^7.14.5", "@types/react": "^18.2.18", @@ -1426,9 +1426,9 @@ } }, "node_modules/@asyncapi/parser": { - "version": "3.0.0-next-major-spec.2", - "resolved": "https://registry.npmjs.org/@asyncapi/parser/-/parser-3.0.0-next-major-spec.2.tgz", - "integrity": "sha512-/gJgCYNYlUSDJhySK3IagjiyFfnwEsAZd5rTe396CB+HxJ6yDWDOZYdHzkFgU2RnCULSGzVOWZGx8t3PK+yuVg==", + "version": "3.0.0-next-major-spec.3", + "resolved": "https://registry.npmjs.org/@asyncapi/parser/-/parser-3.0.0-next-major-spec.3.tgz", + "integrity": "sha512-LCrAQqJpGxraMyU2k1Nh1X6Q1dz7a/YhTRRFFrQHOEo+TUT/kRdoUkRDP++e58dO7h9MBN+/hZK5TaqE+/jQiw==", "dev": true, "dependencies": { "@asyncapi/specs": "^6.0.0-next-major-spec.6", diff --git a/package.json b/package.json index 50f1cfd65..b3700a9b8 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "eslint-plugin-sonarjs": "^0.11.0", "jest": "^27.2.5", "markdown-toc": "^1.2.0", - "@asyncapi/parser": "^3.0.0-next-major-spec.2" + "@asyncapi/parser": "^3.0.0-next-major-spec.3" }, "generator": { "renderer": "react", diff --git a/test/components/Operations.test.js b/test/components/Operations.test.js index eb5be3606..bf01e7113 100644 --- a/test/components/Operations.test.js +++ b/test/components/Operations.test.js @@ -1,65 +1,67 @@ import { render } from '@asyncapi/generator-react-sdk'; -import { AsyncAPIDocumentV2 as AsyncAPIDocument, createAsyncAPIDocument } from '@asyncapi/parser'; +import { AsyncAPIDocumentV2 as AsyncAPIDocument, createAsyncAPIDocument, Parser } from '@asyncapi/parser'; import { Operations } from '../../components/Operations'; +const parser = new Parser(); describe('Operations component', () => { - it('should render operation', () => { - const asyncapi = createAsyncAPIDocument({ - semver: { - major: 2, - minor: 0, - patch: 0, - }, - parsed: { - asyncapi: '2.0.0', - servers: { - rabbitmqBrokerInProd: {}, - rabbitmqBrokerInStaging: {}, + describe('for AsyncAPI v2', () => { + it('should render operation', () => { + const asyncapi = createAsyncAPIDocument({ + semver: { + major: 2, + minor: 0, + patch: 0, }, - channels: { - 'user/signedup': { - description: 'This channel is used to exchange messages about users signing up', - servers: [ - 'rabbitmqBrokerInProd', - 'rabbitmqBrokerInStaging' - ], - subscribe: { - operationId: 'signedupuser', - externalDocs: { - description: 'More info here', - url: 'https://example.com' - }, - tags: [ - { name: 'user' }, - { name: 'signup' }, - { name: 'register' } + parsed: { + asyncapi: '2.0.0', + servers: { + rabbitmqBrokerInProd: {}, + rabbitmqBrokerInStaging: {}, + }, + channels: { + 'user/signedup': { + description: 'This channel is used to exchange messages about users signing up', + servers: [ + 'rabbitmqBrokerInProd', + 'rabbitmqBrokerInStaging' ], - summary: 'A user signed up.', - message: { - name: 'SomeMessage', - description: 'A longer description of the message', - payload: { - type: 'object', - properties: { - user: { - type: 'string' - }, - signup: { - type: 'number' + subscribe: { + operationId: 'signedupuser', + externalDocs: { + description: 'More info here', + url: 'https://example.com' + }, + tags: [ + { name: 'user' }, + { name: 'signup' }, + { name: 'register' } + ], + summary: 'A user signed up.', + message: { + name: 'SomeMessage', + description: 'A longer description of the message', + payload: { + type: 'object', + properties: { + user: { + type: 'string' + }, + signup: { + type: 'number' + } } } } - } + }, }, }, - }, - } - }); - const expected = ` + } + }); + const expected = ` ## Operations -### PUB \`user/signedup\` Operation +### SUB \`user/signedup\` Operation *A user signed up.* @@ -98,66 +100,66 @@ A longer description of the message } \`\`\` `; - - const result = render(); - expect(result.trim()).toEqual(expected.trim()); - }); - - it('should render servers for operation', () => { - const asyncapi = createAsyncAPIDocument({ - semver: { - major: 2, - minor: 0, - patch: 0, - }, - parsed: { - asyncapi: '2.0.0', - servers: { - rabbitmqBrokerInProd: {}, - rabbitmqBrokerInStaging: {}, + + const result = render(); + expect(result.trim()).toEqual(expected.trim()); + }); + + it('should render servers for operation', () => { + const asyncapi = createAsyncAPIDocument({ + semver: { + major: 2, + minor: 0, + patch: 0, }, - channels: { - 'user/signedup': { - description: 'This channel is used to exchange messages about users signing up', - servers: [ - 'rabbitmqBrokerInProd', - ], - subscribe: { - operationId: 'signedupuser', - externalDocs: { - description: 'More info here', - url: 'https://example.com' - }, - tags: [ - { name: 'user' }, - { name: 'signup' }, - { name: 'register' } + parsed: { + asyncapi: '2.0.0', + servers: { + rabbitmqBrokerInProd: {}, + rabbitmqBrokerInStaging: {}, + }, + channels: { + 'user/signedup': { + description: 'This channel is used to exchange messages about users signing up', + servers: [ + 'rabbitmqBrokerInProd', ], - summary: 'A user signed up.', - message: { - name: 'SomeMessage', - description: 'A longer description of the message', - payload: { - type: 'object', - properties: { - user: { - type: 'string' - }, - signup: { - type: 'number' + subscribe: { + operationId: 'signedupuser', + externalDocs: { + description: 'More info here', + url: 'https://example.com' + }, + tags: [ + { name: 'user' }, + { name: 'signup' }, + { name: 'register' } + ], + summary: 'A user signed up.', + message: { + name: 'SomeMessage', + description: 'A longer description of the message', + payload: { + type: 'object', + properties: { + user: { + type: 'string' + }, + signup: { + type: 'number' + } } } } - } + }, }, }, - }, - } - }); - const expected = ` + } + }); + const expected = ` ## Operations -### PUB \`user/signedup\` Operation +### SUB \`user/signedup\` Operation *A user signed up.* @@ -197,37 +199,38 @@ A longer description of the message } \`\`\` `; - - const result = render(); - expect(result.trim()).toEqual(expected.trim()); - }); - - it('should render parameters for operation', () => { - const asyncapi = new AsyncAPIDocument({ - channels: { - 'user/{userId}/signup/{foobar}': { - parameters: { - userId: { - description: 'Id of the user.', - schema: { - type: 'string' + + const result = render(); + expect(result.trim()).toEqual(expected.trim()); + }); + + it('should render parameters for operation', () => { + const asyncapi = new AsyncAPIDocument({ + asyncapi: '2.0.0', + channels: { + 'user/{userId}/signup/{foobar}': { + parameters: { + userId: { + description: 'Id of the user.', + schema: { + type: 'string' + }, + location: '$message.payload#/user/id' }, - location: '$message.payload#/user/id' + foobar: { + schema: { + type: 'string' + }, + } }, - foobar: { - schema: { - type: 'string' - }, - } - }, - publish: {} - } - }, - }); - const expected = ` + publish: {} + } + }, + }); + const expected = ` ## Operations -### SUB \`user/{userId}/signup/{foobar}\` Operation +### PUB \`user/{userId}/signup/{foobar}\` Operation #### Parameters @@ -236,52 +239,53 @@ A longer description of the message | userId | string | Id of the user. | - | - | **required**, **parameter location ($message.payload#/user/id)** | | foobar | string | - | - | - | **required** | `; - - const result = render(); - expect(result.trim()).toEqual(expected.trim()); - }); - - it('should render multiple messages', () => { - const asyncapi = new AsyncAPIDocument({ - channels: { - 'user/{userId}/signup/{foobar}': { - publish: { - message: { - oneOf: [ - { - messageId: 'some-message', - description: 'A longer description of the message', - payload: { - type: 'object', - properties: { - signup: { - type: 'number' + + const result = render(); + expect(result.trim()).toEqual(expected.trim()); + }); + + it('should render multiple messages', () => { + const asyncapi = new AsyncAPIDocument({ + asyncapi: '2.0.0', + channels: { + 'user/{userId}/signup/{foobar}': { + publish: { + message: { + oneOf: [ + { + messageId: 'some-message', + description: 'A longer description of the message', + payload: { + type: 'object', + properties: { + signup: { + type: 'number' + } } } - } - }, - { - name: 'SomeMessage', - description: 'A longer description of the message', - payload: { - type: 'object', - properties: { - user: { - type: 'string' - }, + }, + { + name: 'SomeMessage', + description: 'A longer description of the message', + payload: { + type: 'object', + properties: { + user: { + type: 'string' + }, + } } - } - }, - ] + }, + ] + } } } - } - }, - }); - const expected = ` + }, + }); + const expected = ` ## Operations -### SUB \`user/{userId}/signup/{foobar}\` Operation +### PUB \`user/{userId}/signup/{foobar}\` Operation Accepts **one of** the following messages: @@ -324,56 +328,56 @@ A longer description of the message } \`\`\` `; - - const result = render(); - expect(result.trim()).toEqual(expected.trim()); - }); - - it('should render security', () => { - const asyncapi = createAsyncAPIDocument({ - semver: { - major: 2, - minor: 0, - patch: 0, - }, - parsed: { - asyncapi: '2.0.0', - channels: { - 'smartylighting.streetlights.1.0.action.{streetlightId}.turn.on': { - subscribe: { - security: [ - { - streetlights_auth: [ - 'streetlights:read' - ] - } - ] - } - } + + const result = render(); + expect(result.trim()).toEqual(expected.trim()); + }); + + it('should render security', () => { + const asyncapi = createAsyncAPIDocument({ + semver: { + major: 2, + minor: 0, + patch: 0, }, - components: { - securitySchemes: { - streetlights_auth: { - type: 'oauth2', - description: 'The oauth security descriptions', - flows: { - clientCredentials: { - tokenUrl: 'https://example.com/api/oauth/dialog', - scopes: { - 'streetlights:read': 'Scope required for subscribing to channel', - 'streetlights:write': 'Scope required for publishing to channel' + parsed: { + asyncapi: '2.0.0', + channels: { + 'smartylighting.streetlights.1.0.action.{streetlightId}.turn.on': { + subscribe: { + security: [ + { + streetlights_auth: [ + 'streetlights:read' + ] + } + ] + } + } + }, + components: { + securitySchemes: { + streetlights_auth: { + type: 'oauth2', + description: 'The oauth security descriptions', + flows: { + clientCredentials: { + tokenUrl: 'https://example.com/api/oauth/dialog', + scopes: { + 'streetlights:read': 'Scope required for subscribing to channel', + 'streetlights:write': 'Scope required for publishing to channel' + } } } } } } - } - }, - }); - const expected = ` + }, + }); + const expected = ` ## Operations -### PUB \`smartylighting.streetlights.1.0.action.{streetlightId}.turn.on\` Operation +### SUB \`smartylighting.streetlights.1.0.action.{streetlightId}.turn.on\` Operation #### Additional security requirements @@ -395,62 +399,63 @@ A longer description of the message The oauth security descriptions `; - - const result = render(); - expect(result.trim()).toEqual(expected.trim()); - }); - - it('should render bindings', () => { - const asyncapi = new AsyncAPIDocument({ - channels: { - 'user/{userId}/signup/{foobar}': { - bindings: { - http: { - type: 'request', - method: 'GET', - query: { - type: 'object', - required: [ - 'companyId' - ], - properties: { - companyId: { - type: 'number', - minimum: 1, - description: 'The Id of the company.' - } - }, - additionalProperties: false - }, - bindingVersion: '0.1.0' - }, - }, - publish: { + + const result = render(); + expect(result.trim()).toEqual(expected.trim()); + }); + + it('should render bindings', () => { + const asyncapi = new AsyncAPIDocument({ + asyncapi: '2.0.0', + channels: { + 'user/{userId}/signup/{foobar}': { bindings: { - kafka: { - groupId: { - type: 'string', - enum: [ - 'myGroupId' - ] - }, - clientId: { - type: 'string', - enum: [ - 'myClientId' - ] + http: { + type: 'request', + method: 'GET', + query: { + type: 'object', + required: [ + 'companyId' + ], + properties: { + companyId: { + type: 'number', + minimum: 1, + description: 'The Id of the company.' + } + }, + additionalProperties: false }, bindingVersion: '0.1.0' - } + }, }, + publish: { + bindings: { + kafka: { + groupId: { + type: 'string', + enum: [ + 'myGroupId' + ] + }, + clientId: { + type: 'string', + enum: [ + 'myClientId' + ] + }, + bindingVersion: '0.1.0' + } + }, + } } - } - }, - }); - const expected = ` + }, + }); + const expected = ` ## Operations -### SUB \`user/{userId}/signup/{foobar}\` Operation +### PUB \`user/{userId}/signup/{foobar}\` Operation #### \`http\` Channel specific information @@ -470,33 +475,16 @@ A longer description of the message | clientId | string | - | allowed (\`"myClientId"\`) | - | - | | bindingVersion | - | - | \`"0.1.0"\` | - | - | `; - - const result = render(); - expect(result.trim()).toEqual(expected.trim()); - }); - - it('should render extensions', () => { - const asyncapi = new AsyncAPIDocument({ - channels: { - 'user/{userId}/signup/{foobar}': { - 'x-schema-extensions-as-object': { - type: 'object', - properties: { - prop1: { - type: 'string' - }, - prop2: { - type: 'integer', - minimum: 0 - } - } - }, - 'x-schema-extensions-as-primitive': 'dummy', - 'x-schema-extensions-as-array': [ - 'item1', - 'item2' - ], - publish: { + + const result = render(); + expect(result.trim()).toEqual(expected.trim()); + }); + + it('should render extensions', () => { + const asyncapi = new AsyncAPIDocument({ + asyncapi: '2.0.0', + channels: { + 'user/{userId}/signup/{foobar}': { 'x-schema-extensions-as-object': { type: 'object', properties: { @@ -513,15 +501,33 @@ A longer description of the message 'x-schema-extensions-as-array': [ 'item1', 'item2' - ] + ], + publish: { + 'x-schema-extensions-as-object': { + type: 'object', + properties: { + prop1: { + type: 'string' + }, + prop2: { + type: 'integer', + minimum: 0 + } + } + }, + 'x-schema-extensions-as-primitive': 'dummy', + 'x-schema-extensions-as-array': [ + 'item1', + 'item2' + ] + } } } - } - }); - const expected = ` + }); + const expected = ` ## Operations -### SUB \`user/{userId}/signup/{foobar}\` Operation +### PUB \`user/{userId}/signup/{foobar}\` Operation #### Channel extensions @@ -547,104 +553,575 @@ A longer description of the message | x-schema-extensions-as-array.0 (index) | - | - | \`"item1"\` | - | - | | x-schema-extensions-as-array.1 (index) | - | - | \`"item2"\` | - | - | `; - - const result = render(); - expect(result.trim()).toEqual(expected.trim()); - }); - - it('should render nothing if channels with operations are not defined', () => { - const asyncapi = new AsyncAPIDocument({}); - - const result = render(); - expect(result).toEqual(''); + + const result = render(); + expect(result.trim()).toEqual(expected.trim()); + }); + + it('should render nothing if channels with operations are not defined', () => { + const asyncapi = new AsyncAPIDocument({}); + + const result = render(); + expect(result).toEqual(''); + }); }); - - it('should render reply operation', () => { - const unsubscribeMessaage = { - description: 'Unsubscribe, can specify a channelID or multiple currency pairs.', - payload: { - type: 'object', - properties: { - event: { - type: 'string', - const: 'unsubscribe' + describe('for AsyncAPI v3', () => { + it('should render receive operation', async () => { + const {document, diagnostics} = await parser.parse({ + asyncapi: '3.0.0', + info: { + title: 'test', + version: '1.0.0' + }, + servers: { + rabbitmqBrokerInProd: { + host: 'prod.url:9092', + protocol: 'mqtt' + }, + rabbitmqBrokerInStaging: { + host: 'prod.url:9093', + protocol: 'mqtt' + }, + }, + channels: { + userSignup: { + address: 'user/signedup', + description: 'This channel is used to exchange messages about users signing up', + messages: { + SomeMessage: { + name: 'SomeMessage', + description: 'A longer description of the message', + payload: { + type: 'object', + properties: { + user: { + type: 'string' + }, + signup: { + type: 'number' + } + } + } + } + } } - } - } - }; - const subscribeMessage = { - description: 'Subscribe to a topic on a single or multiple currency pairs.', - payload: { - type: 'object', - properties: { - event: { - type: 'string', - const: 'subscribe' + }, + operations: { + userSignedUp: { + action: 'receive', + channel: { + $ref: '#/channels/userSignup' + }, + externalDocs: { + description: 'More info here', + url: 'https://example.com' + }, + tags: [ + { name: 'user' }, + { name: 'signup' }, + { name: 'register' } + ], + summary: 'A user signed up.', } } - } - }; - const responseMessage = { - description: '', - payload: { - type: 'object', - properties: { - status: { - type: 'number' + }); + + expect(diagnostics).toEqual([]); + const result = render(); + expect(result.trim()).toMatchSnapshot(); + }); + it('should render send operation', async () => { + const {document, diagnostics} = await parser.parse({ + asyncapi: '3.0.0', + info: { + title: 'test', + version: '1.0.0' + }, + servers: { + rabbitmqBrokerInProd: { + host: 'prod.url:9092', + protocol: 'mqtt' + }, + rabbitmqBrokerInStaging: { + host: 'prod.url:9093', + protocol: 'mqtt' + }, + }, + channels: { + userSignup: { + address: 'user/signedup', + description: 'This channel is used to exchange messages about users signing up', + messages: { + SomeMessage: { + name: 'SomeMessage', + description: 'A longer description of the message', + payload: { + type: 'object', + properties: { + user: { + type: 'string' + }, + signup: { + type: 'number' + } + } + } + } + } + } + }, + operations: { + userSignedUp: { + action: 'send', + channel: { + $ref: '#/channels/userSignup' + }, + externalDocs: { + description: 'More info here', + url: 'https://example.com' + }, + tags: [ + { name: 'user' }, + { name: 'signup' }, + { name: 'register' } + ], + summary: 'A user signed up.', } } - } - }; - const channel = { - address: '/', - messages: { - subscribe: subscribeMessage, - unsubscribe: unsubscribeMessaage, - response: responseMessage - } - }; - const asyncapi = createAsyncAPIDocument({ - semver: { - major: 3, - minor: 0, - patch: 0, - }, - parsed: { + }); + + expect(diagnostics).toEqual([]); + const result = render(); + expect(result.trim()).toMatchSnapshot(); + }); + it('should render request operation', async () => { + const {document, diagnostics} = await parser.parse({ asyncapi: '3.0.0', info: { - title: 'Kraken Websockets API', - version: '1.8.0', + title: 'test', + version: '1.0.0' + }, + servers: { + rabbitmqBrokerInProd: { + host: 'prod.url:9092', + protocol: 'mqtt' + }, + rabbitmqBrokerInStaging: { + host: 'prod.url:9093', + protocol: 'mqtt' + }, }, channels: { - currencyExchange: channel + userSignUp: { + address: 'user/signedup', + description: 'This channel is used to exchange messages about users signing up', + messages: { + SomeMessage: { + name: 'SomeMessage', + description: 'A longer description of the message', + payload: { + type: 'object', + properties: { + user: { + type: 'string' + }, + signup: { + type: 'number' + } + } + } + } + } + }, + userSignedUp: { + address: 'user/signedup', + messages: { + SomeReplyMessage: { + name: 'SomeReplyMessage', + description: 'A longer description of the message', + payload: { + type: 'object', + properties: { + user: { + type: 'string' + }, + signup: { + type: 'number' + } + } + } + } + } + } }, operations: { - subscribe: { + userSignUp: { action: 'send', - channel, + channel: { + $ref: '#/channels/userSignUp' + }, + externalDocs: { + description: 'More info here', + url: 'https://example.com' + }, + tags: [ + { name: 'user' }, + { name: 'signup' }, + { name: 'register' } + ], + summary: 'Sign up a user.', reply: { - channel, - messages: [ - responseMessage - ] + channel: { + $ref: '#/channels/userSignedUp' + } + } + } + } + }); + + expect(diagnostics).toEqual([]); + const result = render(); + expect(result.trim()).toMatchSnapshot(); + }); + it('should render reply operation', async () => { + const {document, diagnostics} = await parser.parse({ + asyncapi: '3.0.0', + info: { + title: 'test', + version: '1.0.0' + }, + servers: { + rabbitmqBrokerInProd: { + host: 'prod.url:9092', + protocol: 'mqtt' + }, + rabbitmqBrokerInStaging: { + host: 'prod.url:9093', + protocol: 'mqtt' + }, + }, + channels: { + userSignUp: { + address: 'user/signedup', + description: 'This channel is used to exchange messages about users signing up', + messages: { + SomeMessage: { + name: 'SomeMessage', + description: 'A longer description of the message', + payload: { + type: 'object', + properties: { + user: { + type: 'string' + }, + signup: { + type: 'number' + } + } + } + } } }, - unsubscribe: { + userSignedUp: { + address: 'user/signedup', + messages: { + SomeReplyMessage: { + name: 'SomeReplyMessage', + description: 'A longer description of the message', + payload: { + type: 'object', + properties: { + user: { + type: 'string' + }, + signup: { + type: 'number' + } + } + } + } + } + } + }, + operations: { + userSignUp: { action: 'receive', - channel, + channel: { + $ref: '#/channels/userSignUp' + }, + externalDocs: { + description: 'More info here', + url: 'https://example.com' + }, + tags: [ + { name: 'user' }, + { name: 'signup' }, + { name: 'register' } + ], + summary: 'Sign up a user.', reply: { - channel, - messages: [ - responseMessage - ] + channel: { + $ref: '#/channels/userSignedUp' + } } } } - } + }); + + expect(diagnostics).toEqual([]); + const result = render(); + expect(result.trim()).toMatchSnapshot(); }); - const result = render(); - const actual = result.trim(); - expect(actual).toMatchSnapshot(); + it('should render multiple messages', async () => { + const {document, diagnostics} = await parser.parse({ + asyncapi: '3.0.0', + info: { + title: 'test', + version: '1.0.0' + }, + servers: { + rabbitmqBrokerInProd: { + host: 'prod.url:9092', + protocol: 'mqtt' + }, + rabbitmqBrokerInStaging: { + host: 'prod.url:9093', + protocol: 'mqtt' + }, + }, + channels: { + userSignup: { + address: 'user/{userId}/signup/{foobar}', + parameters: { + userId: { + description: 'Id of the user.', + location: '$message.payload#/user/id' + }, + foobar: {} + }, + description: 'This channel is used to exchange messages about users signing up', + messages: { + SomeMessage: { + name: 'SomeMessage', + description: 'A longer description of the message', + payload: { + type: 'object', + properties: { + user: { + type: 'string' + }, + signup: { + type: 'number' + } + } + } + }, + SomeMessage2: { + messageId: 'SomeMessage2', + description: 'A longer description of the message', + payload: { + type: 'object', + properties: { + signup: { + type: 'number' + } + } + } + } + } + } + }, + operations: { + userSignedUp: { + action: 'send', + channel: { + $ref: '#/channels/userSignup' + }, + externalDocs: { + description: 'More info here', + url: 'https://example.com' + }, + tags: [ + { name: 'user' }, + { name: 'signup' }, + { name: 'register' } + ], + summary: 'A user signed up.', + } + } + }); + + expect(diagnostics).toEqual([]); + const result = render(); + expect(result.trim()).toMatchSnapshot(); + }); + + it('should render bindings for channel', async () => { + const {document, diagnostics} = await parser.parse({ + asyncapi: '3.0.0', + info: { + title: 'test', + version: '1.0.0' + }, + servers: { + rabbitmqBrokerInProd: { + host: 'prod.url:9092', + protocol: 'mqtt' + }, + rabbitmqBrokerInStaging: { + host: 'prod.url:9093', + protocol: 'mqtt' + }, + }, + channels: { + userSignup: { + bindings: { + http: { + type: 'request', + method: 'GET', + query: { + type: 'object', + required: [ + 'companyId' + ], + properties: { + companyId: { + type: 'number', + minimum: 1, + description: 'The Id of the company.' + } + }, + additionalProperties: false + }, + bindingVersion: '0.1.0' + }, + }, + address: 'user/signup', + description: 'This channel is used to exchange messages about users signing up', + messages: { + SomeMessage: { + name: 'SomeMessage', + description: 'A longer description of the message', + payload: { + type: 'object', + properties: { + user: { + type: 'string' + }, + signup: { + type: 'number' + } + } + } + } + } + } + }, + operations: { + userSignedUp: { + action: 'send', + channel: { + $ref: '#/channels/userSignup' + }, + externalDocs: { + description: 'More info here', + url: 'https://example.com' + }, + tags: [ + { name: 'user' }, + { name: 'signup' }, + { name: 'register' } + ], + summary: 'A user signed up.', + } + } + }); + + expect(diagnostics).toEqual([]); + const result = render(); + expect(result.trim()).toMatchSnapshot(); + }); + it('should render bindings for operation', async () => { + const {document, diagnostics} = await parser.parse({ + asyncapi: '3.0.0', + info: { + title: 'test', + version: '1.0.0' + }, + servers: { + rabbitmqBrokerInProd: { + host: 'prod.url:9092', + protocol: 'mqtt' + }, + rabbitmqBrokerInStaging: { + host: 'prod.url:9093', + protocol: 'mqtt' + }, + }, + channels: { + userSignup: { + address: 'user/signup', + description: 'This channel is used to exchange messages about users signing up', + messages: { + SomeMessage: { + name: 'SomeMessage', + description: 'A longer description of the message', + payload: { + type: 'object', + properties: { + user: { + type: 'string' + }, + signup: { + type: 'number' + } + } + } + } + } + } + }, + operations: { + userSignedUp: { + action: 'send', + channel: { + $ref: '#/channels/userSignup' + }, + externalDocs: { + description: 'More info here', + url: 'https://example.com' + }, + tags: [ + { name: 'user' }, + { name: 'signup' }, + { name: 'register' } + ], + summary: 'A user signed up.', + bindings: { + kafka: { + groupId: { + type: 'string', + enum: [ + 'myGroupId' + ] + }, + clientId: { + type: 'string', + enum: [ + 'myClientId' + ] + }, + bindingVersion: '0.1.0' + } + }, + } + } + }); + + expect(diagnostics).toEqual([]); + const result = render(); + expect(result.trim()).toMatchSnapshot(); + }); }); }); diff --git a/test/components/__snapshots__/AsyncAPI.test.js.snap b/test/components/__snapshots__/AsyncAPI.test.js.snap index a93c99659..d9b93f70e 100644 --- a/test/components/__snapshots__/AsyncAPI.test.js.snap +++ b/test/components/__snapshots__/AsyncAPI.test.js.snap @@ -44,7 +44,7 @@ Test broker ## Operations -### SUB \`smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured\` Operation +### PUB \`smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured\` Operation *Inform about environmental lighting conditions of a particular streetlight.* @@ -132,7 +132,7 @@ On multiple lines. | message-tag5 | - | [Find more info here](https://www.asyncapi.com/) | -### PUB \`smartylighting/streetlights/1/0/action/{streetlightId}/turn/on\` Operation +### SUB \`smartylighting/streetlights/1/0/action/{streetlightId}/turn/on\` Operation * Operation ID: \`turnOn\` @@ -191,7 +191,7 @@ On multiple lines. -### PUB \`smartylighting/streetlights/1/0/action/{streetlightId}/turn/off\` Operation +### SUB \`smartylighting/streetlights/1/0/action/{streetlightId}/turn/off\` Operation * Operation ID: \`turnOff\` @@ -250,7 +250,7 @@ On multiple lines. -### PUB \`smartylighting/streetlights/1/0/action/{streetlightId}/dim\` Operation +### SUB \`smartylighting/streetlights/1/0/action/{streetlightId}/dim\` Operation * Operation ID: \`dimLight\` @@ -308,7 +308,7 @@ On multiple lines. -### PUB \`some.channel\` Operation +### SUB \`some.channel\` Operation this description shows in markdown @@ -473,8 +473,7 @@ Kafka DEV cluster for \`dev\` and \`sit\` environments ### REPLY \`adeo-{env}-case-study-COSTING-REQUEST-{version}\` Operation -*[COSTING] Request one or more Costing calculation for any product -* +*[COSTING] Request one or more Costing calculation for any product* * Operation ID: \`requestCosting\` @@ -563,17 +562,16 @@ You can try a costing request using our [Conduktor producer template](https://co #### Response information -* Response should be done to channel: \`adeo-{env}-case-study-COSTING-RESPONSE-{version}\` +* should be done to channel: \`adeo-{env}-case-study-COSTING-RESPONSE-{version}\` #### Operation reply address information * Operation reply address location: \`$message.header#/REPLY_TOPIC\` -### PUB \`adeo-{env}-case-study-COSTING-RESPONSE-{version}\` Operation +### SEND \`adeo-{env}-case-study-COSTING-RESPONSE-{version}\` Operation -*[COSTING] Get the costing responses matching an initial Costing Request. -* +*[COSTING] Get the costing responses matching an initial Costing Request.* * Operation ID: \`getCostingResponse\` diff --git a/test/components/__snapshots__/Operations.test.js.snap b/test/components/__snapshots__/Operations.test.js.snap index 4c80cd458..a9d99bce6 100644 --- a/test/components/__snapshots__/Operations.test.js.snap +++ b/test/components/__snapshots__/Operations.test.js.snap @@ -1,142 +1,360 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Operations component should render reply operation 1`] = ` +exports[`Operations component for AsyncAPI v3 should render bindings for channel 1`] = ` "## Operations -### REQUEST \`/\` Operation +### SEND \`user/signup\` Operation -* Operation ID: \`subscribe\` +*A user signed up.* -Accepts **one of** the following messages: +* Operation ID: \`userSignedUp\` -#### Message \`subscribe\` +This channel is used to exchange messages about users signing up -Subscribe to a topic on a single or multiple currency pairs. +[More info here](https://example.com) + +##### Operation tags + +| Name | Description | Documentation | +|---|---|---| +| user | - | - | +| signup | - | - | +| register | - | - | + +#### \`http\` Channel specific information + +| Name | Type | Description | Value | Constraints | Notes | +|---|---|---|---|---|---| +| type | - | - | \`\\"request\\"\` | - | - | +| method | - | - | \`\\"GET\\"\` | - | - | +| query | object | - | - | - | **additional properties are NOT allowed** | +| query.companyId | number | The Id of the company. | - | >= 1 | **required** | +| bindingVersion | - | - | \`\\"0.1.0\\"\` | - | - | + +#### Message \`SomeMessage\` + +A longer description of the message ##### Payload | Name | Type | Description | Value | Constraints | Notes | |---|---|---|---|---|---| | (root) | object | - | - | - | **additional properties are allowed** | -| event | string | - | const (\`\\"subscribe\\"\`) | - | - | +| user | string | - | - | - | - | +| signup | number | - | - | - | - | > Examples of payload _(generated)_ \`\`\`json { - \\"event\\": \\"subscribe\\" + \\"user\\": \\"string\\", + \\"signup\\": 0 } -\`\`\` +\`\`\`" +`; + +exports[`Operations component for AsyncAPI v3 should render bindings for operation 1`] = ` +"## Operations + +### SEND \`user/signup\` Operation + +*A user signed up.* +* Operation ID: \`userSignedUp\` -#### Message \`unsubscribe\` +This channel is used to exchange messages about users signing up -Unsubscribe, can specify a channelID or multiple currency pairs. +[More info here](https://example.com) + +##### Operation tags + +| Name | Description | Documentation | +|---|---|---| +| user | - | - | +| signup | - | - | +| register | - | - | + +#### \`kafka\` Operation specific information + +| Name | Type | Description | Value | Constraints | Notes | +|---|---|---|---|---|---| +| groupId | string | - | allowed (\`\\"myGroupId\\"\`) | - | - | +| clientId | string | - | allowed (\`\\"myClientId\\"\`) | - | - | +| bindingVersion | - | - | \`\\"0.1.0\\"\` | - | - | + +#### Message \`SomeMessage\` + +A longer description of the message ##### Payload | Name | Type | Description | Value | Constraints | Notes | |---|---|---|---|---|---| | (root) | object | - | - | - | **additional properties are allowed** | -| event | string | - | const (\`\\"unsubscribe\\"\`) | - | - | +| user | string | - | - | - | - | +| signup | number | - | - | - | - | > Examples of payload _(generated)_ \`\`\`json { - \\"event\\": \\"unsubscribe\\" + \\"user\\": \\"string\\", + \\"signup\\": 0 } -\`\`\` +\`\`\`" +`; + +exports[`Operations component for AsyncAPI v3 should render multiple messages 1`] = ` +"## Operations + +### SEND \`user/{userId}/signup/{foobar}\` Operation +*A user signed up.* -#### Message \`response\` +* Operation ID: \`userSignedUp\` + +This channel is used to exchange messages about users signing up + +[More info here](https://example.com) + +##### Operation tags + +| Name | Description | Documentation | +|---|---|---| +| user | - | - | +| signup | - | - | +| register | - | - | + +#### Parameters + +| Name | Type | Description | Value | Constraints | Notes | +|---|---|---|---|---|---| +| userId | string | Id of the user. | - | - | **required**, **parameter location ($message.payload#/user/id)** | +| foobar | string | - | - | - | **required** | + + +Sending **one of** the following messages: + +#### Message \`SomeMessage\` + +A longer description of the message ##### Payload | Name | Type | Description | Value | Constraints | Notes | |---|---|---|---|---|---| | (root) | object | - | - | - | **additional properties are allowed** | -| status | number | - | - | - | - | +| user | string | - | - | - | - | +| signup | number | - | - | - | - | > Examples of payload _(generated)_ \`\`\`json { - \\"status\\": 0 + \\"user\\": \\"string\\", + \\"signup\\": 0 } \`\`\` -#### Request information +#### Message \`SomeMessage2\` + +A longer description of the message + +##### Payload + +| Name | Type | Description | Value | Constraints | Notes | +|---|---|---|---|---|---| +| (root) | object | - | - | - | **additional properties are allowed** | +| signup | number | - | - | - | - | + +> Examples of payload _(generated)_ + +\`\`\`json +{ + \\"signup\\": 0 +} +\`\`\`" +`; -* Request should be done to channel: \`/\` +exports[`Operations component for AsyncAPI v3 should render receive operation 1`] = ` +"## Operations + +### RECEIVE \`user/signedup\` Operation + +*A user signed up.* + +* Operation ID: \`userSignedUp\` +This channel is used to exchange messages about users signing up -### REPLY \`/\` Operation +[More info here](https://example.com) -* Operation ID: \`unsubscribe\` +##### Operation tags -Accepts **one of** the following messages: +| Name | Description | Documentation | +|---|---|---| +| user | - | - | +| signup | - | - | +| register | - | - | -#### Message \`subscribe\` +#### Message \`SomeMessage\` -Subscribe to a topic on a single or multiple currency pairs. +A longer description of the message ##### Payload | Name | Type | Description | Value | Constraints | Notes | |---|---|---|---|---|---| | (root) | object | - | - | - | **additional properties are allowed** | -| event | string | - | const (\`\\"subscribe\\"\`) | - | - | +| user | string | - | - | - | - | +| signup | number | - | - | - | - | > Examples of payload _(generated)_ \`\`\`json { - \\"event\\": \\"subscribe\\" + \\"user\\": \\"string\\", + \\"signup\\": 0 } -\`\`\` +\`\`\`" +`; + +exports[`Operations component for AsyncAPI v3 should render reply operation 1`] = ` +"## Operations + +### REPLY \`user/signedup\` Operation + +*Sign up a user.* + +* Operation ID: \`userSignUp\` + +This channel is used to exchange messages about users signing up + +[More info here](https://example.com) + +##### Operation tags +| Name | Description | Documentation | +|---|---|---| +| user | - | - | +| signup | - | - | +| register | - | - | -#### Message \`unsubscribe\` +#### Message \`SomeMessage\` -Unsubscribe, can specify a channelID or multiple currency pairs. +A longer description of the message ##### Payload | Name | Type | Description | Value | Constraints | Notes | |---|---|---|---|---|---| | (root) | object | - | - | - | **additional properties are allowed** | -| event | string | - | const (\`\\"unsubscribe\\"\`) | - | - | +| user | string | - | - | - | - | +| signup | number | - | - | - | - | > Examples of payload _(generated)_ \`\`\`json { - \\"event\\": \\"unsubscribe\\" + \\"user\\": \\"string\\", + \\"signup\\": 0 } \`\`\` -#### Message \`response\` +#### Response information + +* should be done to channel: \`user/signedup\`" +`; + +exports[`Operations component for AsyncAPI v3 should render request operation 1`] = ` +"## Operations + +### REQUEST \`user/signedup\` Operation + +*Sign up a user.* + +* Operation ID: \`userSignUp\` + +This channel is used to exchange messages about users signing up + +[More info here](https://example.com) + +##### Operation tags + +| Name | Description | Documentation | +|---|---|---| +| user | - | - | +| signup | - | - | +| register | - | - | + +#### Message \`SomeMessage\` + +A longer description of the message ##### Payload | Name | Type | Description | Value | Constraints | Notes | |---|---|---|---|---|---| | (root) | object | - | - | - | **additional properties are allowed** | -| status | number | - | - | - | - | +| user | string | - | - | - | - | +| signup | number | - | - | - | - | > Examples of payload _(generated)_ \`\`\`json { - \\"status\\": 0 + \\"user\\": \\"string\\", + \\"signup\\": 0 } \`\`\` -#### Response information +#### Request information + +* should be done to channel: \`user/signedup\`" +`; + +exports[`Operations component for AsyncAPI v3 should render send operation 1`] = ` +"## Operations + +### SEND \`user/signedup\` Operation + +*A user signed up.* + +* Operation ID: \`userSignedUp\` + +This channel is used to exchange messages about users signing up + +[More info here](https://example.com) + +##### Operation tags + +| Name | Description | Documentation | +|---|---|---| +| user | - | - | +| signup | - | - | +| register | - | - | -* Response should be done to channel: \`/\`" +#### Message \`SomeMessage\` + +A longer description of the message + +##### Payload + +| Name | Type | Description | Value | Constraints | Notes | +|---|---|---|---|---|---| +| (root) | object | - | - | - | **additional properties are allowed** | +| user | string | - | - | - | - | +| signup | number | - | - | - | - | + +> Examples of payload _(generated)_ + +\`\`\`json +{ + \\"user\\": \\"string\\", + \\"signup\\": 0 +} +\`\`\`" `;