event-catalog / generator-asyncapi

AsyncAPI generator for EventCatalog
https://www.eventcatalog.dev/docs/development/integrations/async-api/intro
Other
9 stars 4 forks source link

Invalid asyncapi document generated within service #27

Closed IsmaelMartinez closed 1 month ago

IsmaelMartinez commented 1 month ago

Context

The generator for asyncapi generates invalid async api document in the service. This fails then to load.

Using this configuration file (the simple example in the asyncapi studio):

asyncapi: 3.0.0
info:
  title: Account Service
  version: 1.0.0
  description: This service is in charge of processing user signups
channels:
  userSignedup:
    address: user/signedup
    messages:
      UserSignedUp:
        $ref: '#/components/messages/UserSignedUp'
operations:
  sendUserSignedup:
    action: send
    channel:
      $ref: '#/channels/userSignedup'
    messages:
      - $ref: '#/channels/userSignedup/messages/UserSignedUp'
components:
  messages:
    UserSignedUp:
      payload:
        type: object
        properties:
          displayName:
            type: string
            description: Name of the user
          email:
            type: string
            format: email
            description: Email of the user

This generates the following asyncapi file within the service:

asyncapi: 3.0.0
info:
  title: Account Service
  version: 1.0.0
  description: This service is in charge of processing user signups
channels:
  userSignedup:
    address: user/signedup
    messages:
      UserSignedUp:
        payload:
          type: object
          properties:
            displayName:
              type: string
              description: Name of the user
              x-parser-schema-id: <anonymous-schema-2>
            email:
              type: string
              format: email
              description: Email of the user
              x-parser-schema-id: <anonymous-schema-3>
          x-parser-schema-id: <anonymous-schema-1>
        x-parser-unique-object-id: UserSignedUp
        x-parser-message-name: UserSignedUp
    x-parser-unique-object-id: userSignedup
operations:
  sendUserSignedup:
    action: send
    channel:
      address: user/signedup
      messages:
        UserSignedUp:
          payload:
            type: object
            properties:
              displayName:
                type: string
                description: Name of the user
                x-parser-schema-id: <anonymous-schema-2>
              email:
                type: string
                format: email
                description: Email of the user
                x-parser-schema-id: <anonymous-schema-3>
            x-parser-schema-id: <anonymous-schema-1>
          x-parser-unique-object-id: UserSignedUp
          x-parser-message-name: UserSignedUp
      x-parser-unique-object-id: userSignedup
    messages:
      - payload:
          type: object
          properties:
            displayName:
              type: string
              description: Name of the user
              x-parser-schema-id: <anonymous-schema-2>
            email:
              type: string
              format: email
              description: Email of the user
              x-parser-schema-id: <anonymous-schema-3>
          x-parser-schema-id: <anonymous-schema-1>
        x-parser-unique-object-id: UserSignedUp
        x-parser-message-name: UserSignedUp
    x-parser-unique-object-id: sendUserSignedup
components:
  messages:
    UserSignedUp:
      payload:
        type: object
        properties:
          displayName:
            type: string
            description: Name of the user
            x-parser-schema-id: <anonymous-schema-2>
          email:
            type: string
            format: email
            description: Email of the user
            x-parser-schema-id: <anonymous-schema-3>
        x-parser-schema-id: <anonymous-schema-1>
      x-parser-unique-object-id: UserSignedUp
      x-parser-message-name: UserSignedUp
x-parser-spec-parsed: true
x-parser-api-version: 3

The problem seems to be around the operations -> sendUserSignedup -> channel image

This results on the asyncAPI not rendering on the UI.

Expected behavior

For the template to generate a valid asyncapi file inside the service.

Other details

generator-asyncapi version: 0.1.3

IsmaelMartinez commented 1 month ago

It might be a side effect from this change https://github.com/event-catalog/generator-asyncapi/pull/20

I think you might just be able to use https://github.com/asyncapi/parser-js/blob/master/packages/parser/src/stringify.ts#L13C17-L13C26 function from the parser.

Here the docs. https://github.com/asyncapi/parser-js?tab=readme-ov-file#stringify

I can give it a go if you are happy for me to try to fix it.

IsmaelMartinez commented 1 month ago

To clarify on the issue, the problem is on the file EventCatalog generates inside the service. If you download the spec and check it in https://studio.asyncapi.com/ it just complains with some de-reference error.

I did try using the stringify function from parser-js, as it reads as what we need, but it doesn't work out of the box. That function it generates a sort of json pointers (with with . donation) and adds a $ref:$. in front of it.

You can use a replacerFunction to revert those changes, and this seems to work in small files, but larger ones doesn't as it looks the stringify has done its job properly, and I think there is a traverse issue in https://github.com/asyncapi/parser-js/blob/master/packages/parser/src/stringify.ts#L93.

However, I think the parser-js could just use the https://github.com/asyncapi/optimizer instead. I will check that later on and see if that works. If that works I will see if I can apply it in the parser-js library

IsmaelMartinez commented 1 month ago

for info, there is a conversation happening in https://discord.com/channels/918092420338569216/1282993103372025927 . I try to keep this updated with any relevant finding that might be useful for the future.

IsmaelMartinez commented 1 month ago

Ok, the problem was mostly on my spec files.

I was referencing the messages in my channels like this (incorrect):

channels:
    inventoryReserved:
        address: inventory/reserved
        messages:
          - $ref: '#/components/messages/InventoryReserved'

And then using them in the operations like this:

operations:
     receiveInventoryReserved:
          action: receive
          channel:
              $ref: '#/channels/inventoryReserved'
          messages:
              - $ref: '#/channels/inventoryReserved/messages/InventoryReserved'

This got the parser confused and generated multiple references to the messages.

Option A: If you got a channel with only one message, you can reference it as I have initially put,

channels:
    inventoryReserved:
        address: inventory/reserved
        messages:
          - $ref: '#/components/messages/InventoryReserved'

but then your operations should not include a message:

operations:
   receiveInventoryReserved:
       action: receive
          channel:
              $ref: '#/channels/inventoryReserved'

Option B: If you have multiple messages that need to go to one channel, then you should create your channels with this format:

channels:
    inventoryReserved:
        address: inventory/reserved
        messages:
            InventoryReserved:
                $ref: '#/components/messages/InventoryReserved'
            AnotherMessage:
                $ref: '#/components/messages/AnotherMessage'

Then you need to reference the message from the channel like this:

operations:
     receiveInventoryReserved:
          action: receive
          channel:
              $ref: '#/channels/inventoryReserved'
          messages:
              - $ref: '#/channels/inventoryReserved/messages/InventoryReserved'

This issue can be closed as it only generates a warning, not an error. We can do an enhancement for the warning, but is not the end of the world as all seems to work ok.

Apologies for the noise but is all a learning 😄