# AsyncAPI gets a new version 3.0 and new operations

Author: [Mete Atamel](https://atamel.dev/) | Published: 2024-05-13 | Topics: AsyncAPI, Event-driven, How To | Canonical: https://atamel.dev/posts/2024/05-13_asyncapi_30_send_receive/


Almost one year ago, I talked about [AsyncAPI](https://www.asyncapi.com/) `2.6` and
how confusing its `publish` and `subscribe` operations can be in my [Understanding
AsyncAPI's publish & subscribe semantics with an
example](/posts/2023/05-18_asyncapi_publishsubscribe_refactor) post.

Since then, a new `3.0` version of AsyncAPI has been released with breaking changes
and a totally new `send` and `receive` operations.

In this blog post, I want to revisit the example from last year and show how to
rewrite it for AsyncAPI `3.0` with the new `send` and `receive` operations.

## AsyncAPI 3.0

AsyncAPI `3.0` was released in December 2023. Since it's a major version, it
has some breaking changes. These two pages does a good job explaining the
changes and the rationale behind them:

* [AsyncAPI 3.0.0 Release Notes](https://www.asyncapi.com/blog/release-notes-3.0.0).
* [Migrating to v3](https://www.asyncapi.com/docs/migration/migrating-to-v3).

I won't go through all the changes. For me, the biggest change is the separation
of operations and channels, and changing `publish` and `subscribe` operations to
`send` and `receive`.

![AsyncAPI 2.6 vs 3.0](/img/2024/asyncapi_26_30.png "AsyncAPI 2.6 vs 3.0")

## Recap: Publish and subscribe operations in AsyncAPI 2.6

As a recap, AsyncAPI `2.6` has the following `publish` and `subscribe`
operations with these semantics:

| AsyncAPI Term | From Server Perspective | From User Perspective |
| --- | --- | --- |
| Publish | Server receives the message | User publishes messages to the server |
| Subscribe | Server sends the message | User subscribes for messages from the server |

In `2.6`, `publish` and `subscribe` operations are from **user's perspective**.

## New: Send and receive operations in AsyncAPI 3.0

In `3.0`, the `publish` and `subscribe` operations are replaced with
`send` and `receive` operations. In [Migrating to
v3](https://www.asyncapi.com/docs/migration/migrating-to-v3) page, the rationale is
given as follows:

> In v2, the publish and subscribe operations consistently caused confusion, even among those familiar with the intricacies.
>
> When you specified publish, it implied that others could publish to this
> channel since your application subscribed to it.
> Conversely, subscribe meant that others could subscribe because your application was the one publishing.
>
> In v3, these operations have been entirely replaced with an action property
> that clearly indicates what your application does. That eliminates
> ambiguities related to other parties or differing perspectives.

While I agree that `publish` and `subscribe` were confusing, I'm not sure if
`send` and `receive` are less confusing. You still need to talk about whose
perspective when defining these operations. AsyncAPI docs talk about
*application* but that's not clear either. Does application refer to the code
sending the message (user) or the code receiving the message (server)?

In Async `3.0`, `send` and `receive` operations are from **server's
perspective**. An example will clarify.

## Account and Email Services

Let's revisit our example from last year. You have two microservices:
`Account Service` emits an `userSignedUp` event and `Email Service` receives that event:

![Account and Email services](https://camo.githubusercontent.com/36279498ca85bf6339a037e9d7ab665ef0b2b7990aec984433ff7463e2b18337/68747470733a2f2f6d69726f2e6d656469756d2e636f6d2f76322f726573697a653a6669743a3732302f666f726d61743a776562702f312a704e7649566959347835765a684f6c6e4d38647155772e706e67)

How do you define such an architecture in AsyncAPI `2.6` vs `3.0`?

## Account Service

For `Account Service`, in `2.6`, you had to define a channel with `subscribe`
operation because the **user** has to subscribe to receive messages:

```yaml
asyncapi: 2.6.0

channels:
  user/signedup:
    subscribe:
      operationId: publishUserSignedUp
      message:
        $ref: '#/components/messages/userSignedUp'
```

[account-service-2.6.yaml](https://github.com/meteatamel/asyncapi-basics/blob/main/samples/account-email-services/account-service-2.6.yaml)

In `3.0`, the channel does not have an operation anymore. Instead, there's a new
`publishUserSignedUp` operation with `send` action that refers to the channel.
This is because the **server** sends the message:

```yaml
asyncapi: 3.0.0

channels:
  user/signedup:
    address: user/signedup
    messages:
      publishUserSignedUp.message:
        $ref: '#/components/messages/userSignedUp'

operations:
  publishUserSignedUp:
    action: send
    channel:
      $ref: '#/channels/user~1signedup'
    messages:
      - $ref: '#/channels/user~1signedup/messages/publishUserSignedUp.message'
```

[account-service-3.0.yaml](https://github.com/meteatamel/asyncapi-basics/blob/main/samples/account-email-services/account-service-3.0.yaml)

## Email Service

Similarly, in `Email Service`, in `2.6`, you had to define a `publish` operation
because the **user** had to publish a message to the server:

```yaml
asyncapi: 2.6.0

channels:
  user/signedup:
    publish:
      operationId: receiveUserSignedUp
      message:
        $ref : '#/components/messages/userSignedUp'
```

[email-service-2.6.yaml](https://github.com/meteatamel/asyncapi-basics/blob/main/samples/account-email-services/email-service-2.6.yaml)

However, in `3.0`, the **server** receives a message, so the operation has
`receive` action:

```yaml
asyncapi: 3.0.0

channels:
  user/signedup:
    address: user/signedup
    messages:
      receiveUserSignedUp.message:
        $ref: '#/components/messages/userSignedUp'

operations:
  receiveUserSignedUp:
    action: receive
    channel:
      $ref: '#/channels/user~1signedup'
    messages:
      - $ref: '#/channels/user~1signedup/messages/receiveUserSignedUp.message'
```

---

In this blog post, I explored a small part of AsyncAPI and explained the
differences between `2.6` operations `publish` and `subscribe` and `3.0`
operations `send` and `receive`. In a nutshell, in `2.6`, you need to think from
user's perspective and in `3.0` in server's perspective when you define these
operations.

If you're interested in learning more, I have a talk on CloudEvents and
AsyncAPI and a repo with some samples:

* [Open standards for building event-driven applications in the
  cloud](https://speakerdeck.com/meteatamel/open-standards-for-building-event-driven-applications-in-the-cloud). 
* [asyncapi-basics](https://github.com/meteatamel/asyncapi-basics/)

