Skip to content

Commit

Permalink
Merge branch 'next-major-spec' into add_parameter_section
Browse files Browse the repository at this point in the history
  • Loading branch information
jonaslagoni authored Nov 17, 2023
2 parents b52f7d8 + 4fecf10 commit ad9be7a
Show file tree
Hide file tree
Showing 31 changed files with 2,642 additions and 17,056 deletions.
4 changes: 2 additions & 2 deletions components/Asyncapi3Comparison.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export function Asyncapi3ChannelComparison({ className = '' }) {
Channels

<div className={(hoverState.PathItem ? `bg-yellow-300` : 'bg-white') + ` border border-yellow-600 p-2 m-2`} onMouseOver={() => setHoverState(prevState => ({ ...prevState, PathItem: true }))} onMouseLeave={() => setHoverState({ PathItem: false })}>
Channel Item
Channel
<div className="flex flex-col flex-wrap flex-1">
<div className={(hoverState.Message ? `bg-red-400` : 'bg-white') + ` flex-1 border border-red-600 p-2 m-2`} onMouseEnter={() => setHoverState(prevState => ({ ...prevState, Message: true }))} onMouseLeave={() => setHoverState({ Message: false })}>
Messages
Expand Down Expand Up @@ -134,7 +134,7 @@ export function Asyncapi3IdAndAddressComparison({ className = '' }) {
Channels

<div className={(hoverState.PathItem ? `bg-yellow-300` : 'bg-white') + ` border border-yellow-600 p-2 m-2`} onMouseOver={() => setHoverState(prevState => ({ ...prevState, PathItem: true }))} onMouseLeave={() => setHoverState({ PathItem: false })}>
Channel Item
Channel

<div className="flex flex-col flex-wrap flex-1">
<div className="border border-blue-500 bg-white hover:bg-blue-200 p-2 m-2">
Expand Down
14 changes: 8 additions & 6 deletions components/GeneratorInstallation.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ export default function GeneratorInstallation({ }) {
}

function getNpmCode() {
return `npm install -g @asyncapi/generator
ag ${specPath} ${template} ${params}`
return `npm install -g @asyncapi/cli
asyncapi generate fromTemplate ${specPath} ${template} ${params}`
}

function getDockerCode() {
return `docker run --rm -it -v \${PWD}/example:/app/example \\
asyncapi/generator ${specPath} ${template} ${params}`
return `docker run --rm -it -v \${PWD}/example:/app/example -v \${PWD}/output:/app/output \\
asyncapi/cli generate fromTemplate ${specPath} ${template} ${params}`
}

return (
Expand All @@ -56,10 +56,12 @@ asyncapi/generator ${specPath} ${template} ${params}`
codeBlocks={[{
language: 'npm',
code: getNpmCode(),
}, {
},
{
language: 'Docker',
code: getDockerCode(),
}]}
},
]}
/>
</div>
)
Expand Down
226 changes: 226 additions & 0 deletions components/OpenAPIComparisonV3.js

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions pages/docs/concepts/asyncapi-document/_section.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
title: 'AsyncAPI Document'
weight: 50
---
158 changes: 158 additions & 0 deletions pages/docs/concepts/asyncapi-document/adding-bindings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
---
title: Adding Bindings
weight: 260
---

Bindings in AsyncAPI provide a way to add protocol-specific information to the AsyncAPI documentation. They can be added to different document parts, such as servers, channels, or messages; they specify standard details specific to a particular protocol. The purpose of bindings is to enhance the API's understanding and usage by providing additional context and configuration options for different protocols.

The following diagram highlights the sections where bindings can be implemented:

```mermaid
graph TD
A[AsyncAPI Document] --> B((Servers))
A --> D((Channels))
A --> E((Operations))
D --> F((Messages))
B --> C{Server Bindings}
D --> G{Channel Bindings}
E --> H{Operation Bindings}
F --> I{Message Bindings}
style C fill:#47BCEE,stroke:#47BCEE;
style G fill:#47BCEE,stroke:#47BCEE;
style H fill:#47BCEE,stroke:#47BCEE;
style I fill:#47BCEE,stroke:#47BCEE;
```


## Server bindings

Server bindings provide protocol-specific information related to the server configuration. For example, if you use Pulsar as your message broker, you can specify the tenant name in the server bindings.

Here is a diagram explaining server bindings:

```mermaid
graph LR
A[AsyncAPI Document] --> B((Servers))
B --> C{Server Bindings}
style C fill:#47BCEE,stroke:#47BCEE;
```

This diagram shows where server bindings fit into the AsyncAPI document structure.

The next example showcases how to use server bindings to detail protocol-specific configurations for the server:

```yml
servers:
production:
bindings:
pulsar:
tenant: contoso
bindingVersion: '0.1.0'
```
The previous document shows how to set up server bindings for a server that is a Pulsar broker.
## Channel bindings
Channel bindings are used to specify protocol-specific information for a specific channel. For example, in Kafka, you can specify number of partitions for a given topic.
Here is a diagram explaining where channel bindings fit into the AsyncAPI document structure:
```mermaid
graph LR
A[AsyncAPI Document] --> D((Channels))
D --> G{Channel Bindings}

style G fill:#47BCEE,stroke:#47BCEE;
```


Here is an example of using channel bindings to specify protocol-specific information for a specific channel:

```yml
channels:
user-signedup:
bindings:
kafka:
topic: 'my-specific-topic-name'
partitions: 20
replicas: 3
topicConfiguration:
cleanup.policy: ["delete", "compact"]
retention.ms: 604800000
retention.bytes: 1000000000
delete.retention.ms: 86400000
max.message.bytes: 1048588
bindingVersion: '0.4.0'
```
The previous document shows how to configure channel bindings for a Kafka topic-representative channel.
## Message bindings
Message bindings provide protocol-specific information for a specific message. For example, for the AMQP protocol, you can specify the message type in a protocol-specific notation.
Here is a diagram explaining where message bindings fit into the AsyncAPI document structure:
```mermaid
graph LR
A[AsyncAPI Document] --> F((Channels))
F --> G{Message Bindings}

style G fill:#47BCEE,stroke:#47BCEE;
```


Here is an example of using message bindings to provide protocol-specific information for a specific message:

```yml
channels:
userSignup:
address: 'user/signup'
messages:
userSignupMessage:
bindings:
amqp:
contentEncoding: gzip
messageType: 'user.signup'
bindingVersion: 0.3.0
```
The previous document shows how to set up message bindings for a message transported using the AMQP protocol.
## Operation bindings
Operation bindings allow you to specify protocol-specific information for a specific operation. For example, for MQTT, you can specify the quality of the service for a given operation.
Here is a diagram explaining where operation bindings fit into the AsyncAPI document structure:
```mermaid
graph LR
A[AsyncAPI Document] --> D((Channels))
D --> E{Operations}
E --> H{Operation Bindings}

style H fill:#47BCEE,stroke:#47BCEE;
```


Here is an example of using operation bindings to specify protocol-specific information for a specific operation:

```yml
channels:
user/signup:
operations:
userSignup:
action: receive
bindings:
mqtt:
qos: 2
retain: true
bindingVersion: 0.2.0
```
The previous document shows how to set up operation bindings for an operation that describes how an application that uses MQTT as transport, receives the message.
Using bindings helps you enhance the AsyncAPI documentation with protocol-specific details, making it easier to understand and implement the API.
141 changes: 141 additions & 0 deletions pages/docs/concepts/asyncapi-document/reply-info.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
---
title: Adding reply info
weight: 210
---

Request/Reply is a communication pattern where one entity, the 'requestor,' sends a message to another, the 'replier', and waits for a response. Such a pattern is used when a component (or service) needs to initiate an action and receive a specific response in return, either synchronously or asynchronously. In Event-Driven Architectures, this communication pattern is asynchronous, meaning that the requester does not block and wait for an immediate response. Instead, it can continue processing other tasks or even send out other requests while waiting for the reply to arrive.

In the case of multiple requests made, each request is processed independently and sends the reply/response to the corresponding requestor when ready.

Here is diagram to illustrate the working of a basic request/reply pattern:
```mermaid
sequenceDiagram
Requester->>Channels: Send Request through Channel A
Channels->>Responder: Deliver Request
activate Responder
Responder-->>Channels: Send Reply through Channel B
deactivate Responder
Channels-->>Requester: Deliver Reply
```

The request/reply pattern in AsyncAPI works in the same fashion while supporting all the different sub-patterns. Irrespective of the sub-pattern you would like to represent, the request/reply pattern can be implemented in the AsyncAPI document in the `Operation` object.

You can add the reply info using the `Operation Reply` object under the `Operation` object. The `reply` field represents the response details.

In AsyncAPI, you have the flexibility to represent the request/reply pattern in two different ways.

The first approach is when the requester specifies at runtime, within the request itself, where the response should be sent. Such an approach allows for the dynamic determination of the reply address based on factors such as the request message payload or header.

The second approach is when the requester already knows exactly where the response should be sent. In such cases, the address of the reply channel is directly specified in the AsyncAPI document.

## Dynamic response channel

There are situations where you do not know the reply channel at the design time. Instead, the reply address is dynamically determined at runtime, based on factors such as the request message payload or header.

In the case where you don't know the address of the reply yet, you have the option to either assign null to the `address` property or omit the property entirely indicating that the address is not known at the moment. The `address` property being referred to in this case is part of the channel that the operation with the reply references to. To dynamically specify where the reply should be sent, you can use the `Operation Reply Address` object. The `Operation Reply Address` object has a property called `location` that allows you to define a runtime expression that specifies the address of the reply channel.

For instance, this pattern allows the replier to direct its response to a specific channel as defined by the requestor. This is typically achieved by including a `replyTo` property in the request header. The requestor specifies this property to indicate where it expects to receive the response, guiding the communication flow in a structured and predictable manner.

```yml
asyncapi: 3.0.0

info:
title: Ping/pong example for a requester with a dynamic reply channel
version: 1.0.0
description: Example with a requester that initiates a request/reply interaction, with the response directed to the destination specified in the request's `replyTo` header.

channels:
ping:
address: /ping
messages:
ping:
$ref: '#/components/messages/ping'
pong:
address: null
messages:
pong:
$ref: '#/components/messages/pong'

operations:
pingRequest:
action: send
channel:
$ref: '#/channels/ping'
reply:
address:
description: The response destination is dynamically set according to the `replyTo` field in the request header
location: "$message.header#/replyTo"
channel:
$ref: '#/channels/pong'
```
## Multiple channels with single message when reply address is known
The request/reply pattern can also be implemented over multiple channels with a single message. You can do this by specifying multiple channels with a single message and specifying the same address for both the requester and the replier.
Here's an example of setting up both the requestor and replier over the same address:
```yml
asyncapi: 3.0.0

info:
title: Ping/pong example with requester over the same channel
version: 1.0.0
description: Requester example initiating a request-reply interaction, utilizing the same channel for both sending the request and receiving the reply.

channels:
ping:
address: /
messages:
ping:
$ref: '#/components/messages/ping'
pong:
address: /
messages:
pong:
$ref: '#/components/messages/pong'

operations:
pingRequest:
action: send
channel:
$ref: '#/channels/ping'
reply:
channel:
$ref: '#/channels/pong'
```
## Multiple messages over the same channel when reply address is known
In some cases, representing the [same information](#multiple-channels-with-single-message) might require a different approach. You can do so by specifying multiple messages under the same channel. In such scenarios, use the `messages` property in the `Operation` object to explicitly define which message among the multiple messages available over the same channel is a request and which is a reply.

Consider an example where multiple messages are transmitted over a single channel, all sharing the same address. In this setup, the `Operation` object is utilized to distinctly specify which of these messages serves as the request and which functions as the reply:
```yml
asyncapi: 3.0.0
info:
title: Ping/pong example when a channel contains multiple messages
version: 1.0.0
description: Requester example that initiates the request-reply pattern within a root channel that contains multiple messages
channels:
rootChannel:
address: /
messages:
ping:
$ref: '#/components/messages/ping'
pong:
$ref: '#/components/messages/pong'
operations:
pingRequest:
action: send
channel:
$ref: '#/channels/rootChannel'
messages:
- $ref: "/components/messages/ping"
reply:
messages:
- $ref: "/components/messages/pong"
channel:
$ref: '#/channels/rootChannel'
```
Loading

0 comments on commit ad9be7a

Please sign in to comment.