asyncapi-codegen icon indicating copy to clipboard operation
asyncapi-codegen copied to clipboard

Header object will always be called "headers" in types. This causes conflict with many channels, using the same headers! (as two structs with same name will be generated)

Open omegagussan opened this issue 6 months ago • 4 comments

For the example:

asyncapi: 3.0.0
defaultContentType: application/json
info:
  title: User Service
  version: 0.30.0
  description: AsyncAPI 3.0 spec using GCP Pub/Sub with traits and external refs.

channels:
  userSignedUpV2:
    address: user-signed-up
    messages:
      userSignedUpMessageV2:
        $ref: '#/components/messages/UserSignedUpMessageV2'
  userSignedUp:
    address: user-signed-up
    messages:
      userSignedUpMessage:
        $ref: '#/components/messages/UserSignedUpMessage'

operations:
  handleUserSignedUp:
    action: send
    channel:
      $ref: '#/channels/userSignedUp'

  handleUserSignedUpV2:
    action: send
    channel:
      $ref: '#/channels/userSignedUpV2'

components:
  messages:
    UserSignedUpMessageV2:
      name: UserSignedUp
      title: User Signed Up Event
      contentType: application/json
      payload:
        $ref: '#/components/schemas/UserSignedUpPayloadV2'
      #obs! This must be relative to file running the generator
      traits:
        - $ref: 'envelope.yaml#/components/messageTraits/CommonHeaders'
      correlationId:
        description: Default Correlation ID
        location: $message.header#/correlationId

    UserSignedUpMessage:
      name: UserSignedUp
      title: User Signed Up Event
      contentType: application/json
      payload:
        $ref: '#/components/schemas/UserSignedUpPayload'
      #obs! This must be relative to file running the generator
      traits:
        - $ref: 'envelope.yaml#/components/messageTraits/CommonHeaders'
      correlationId:
        description: Default Correlation ID
        location: $message.header#/correlationId

  schemas:
    # Remove email as required field
    UserSignedUpPayloadV2:
      type: object
      required: [id]
      properties:
        id:
          type: string
          format: uuid
        email:
          type: string
          format: email

    UserSignedUpPayload:
      type: object
      required: [id, email]
      properties:
        id:
          type: string
          format: uuid
        email:
          type: string
          format: email

with the commonTraits basically being an envelope format for pubsub like so to allow filtering etc.

asyncapi: 3.0.0
info:
  title: Envelope Schema
  version: 0.0.1
  description: Common envelope schema for Pub/Sub messages with traits and external references.

components:
    messageTraits:
        CommonHeaders:
          headers:
            type: object
            properties:
              correlationId:
                type: string
                description: Correlation ID for tracing (traceId in OpenTelemetry)
              timestamp:
                type: string
                format: date-time
              version:
                type: string
                description: Semantic version of server for the message
              payloadType:
                type: string
                description: Type of the payload being sent
              schemaLocation:
                type: string
                description: Location of the schema for the message

this will generate conflicting types in the generated code:

// UserSignedUpMessageV2Message is the message expected for 'UserSignedUpMessageV2Message' channel.
type UserSignedUpMessageV2Message struct {
	// Headers will be used to fill the message headers
	Headers Header

	// Payload will be inserted in the message payload
	Payload UserSignedUpPayloadV2Schema
}
...
// UserSignedUpMessageMessage is the message expected for 'UserSignedUpMessageMessage' channel.
type UserSignedUpMessageMessage struct {
	// Headers will be used to fill the message headers
	Headers Header

	// Payload will be inserted in the message payload
	Payload UserSignedUpPayloadSchema
}

both these messages refer the same Headers Header! Good. Except its also generated twice in the file. So it does not compile later. "'Header' redeclared in this package" (and in my file it happens to be on line 226 and line 85 when generating only the types.

omegagussan avatar Jun 25 '25 12:06 omegagussan

Im trying to look into this myself to see if we can deduplicate this "headers" or name them in a unique way to avoid the conflict. Best would be to realize its the same headers and only generate the type once in the output.

omegagussan avatar Jun 25 '25 12:06 omegagussan

Ok, I figured out what the real bug was after creating this testcase:

The problem is actually when you add the correlationId then we start seeing this new header "header" apperar. This is a problem. I will rephrase the issue.

omegagussan avatar Jun 26 '25 11:06 omegagussan

https://github.com/lerenn/asyncapi-codegen/pull/284

omegagussan avatar Jun 26 '25 11:06 omegagussan

Hello @omegagussan , thanks for reporting this issue !

I'll try to take a look in the next days, but feel free to propose a fix if you want to :)

lerenn avatar Jun 27 '25 08:06 lerenn