{"id":37272554,"url":"https://github.com/evryfs/asyncapi-generator","last_synced_at":"2026-04-02T12:00:15.816Z","repository":{"id":332464634,"uuid":"1111431895","full_name":"evryfs/asyncapi-generator","owner":"evryfs","description":"AsyncAPI Code Generator ","archived":false,"fork":false,"pushed_at":"2026-03-24T09:59:22.000Z","size":775,"stargazers_count":3,"open_issues_count":2,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-24T19:55:48.863Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/evryfs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-06T23:20:30.000Z","updated_at":"2026-03-24T07:12:38.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/evryfs/asyncapi-generator","commit_stats":null,"previous_names":["evryfs/asyncapi-generator"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/evryfs/asyncapi-generator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evryfs%2Fasyncapi-generator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evryfs%2Fasyncapi-generator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evryfs%2Fasyncapi-generator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evryfs%2Fasyncapi-generator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/evryfs","download_url":"https://codeload.github.com/evryfs/asyncapi-generator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evryfs%2Fasyncapi-generator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31305971,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T09:48:21.550Z","status":"ssl_error","status_checked_at":"2026-04-02T09:48:19.196Z","response_time":89,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-16T00:45:41.161Z","updated_at":"2026-04-02T12:00:15.793Z","avatar_url":"https://github.com/evryfs.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# asyncapi-generator\n\nThe asyncapi-generator is an open-source tool for generating code and schemas from AsyncAPI Yaml specifications.\n\nThe project is currently in BETA.\n\n## Supported generators\n\n- Kotlin - Data classes with Jakarta Validation annotations\n- Java - POJOs with Jakarta Validation annotations\n- Spring Kafka - Producer and Consumer templates for both Kotlin and Java\n- Avro - Schema generation from AsyncAPI schemas\n\nThe current documentation provided is still a draft, found in `docs/` folder at the repository root.\n\n## Usage\n\nCurrently, the asyncapi-generator BETA version is available as a maven plugin through maven central.\n\nExample usage in your `pom.xml`:\n\n```xml\n\u003cplugin\u003e\n    \u003cgroupId\u003edev.banking.asyncapi.generator\u003c/groupId\u003e\n    \u003cartifactId\u003easyncapi-generator-maven-plugin\u003c/artifactId\u003e\n    \u003cversion\u003e0.0.1\u003c/version\u003e \u003c!-- current BETA version --\u003e\n    \u003cexecutions\u003e\n        \u003cexecution\u003e\n            \u003cid\u003egenerate-example\u003c/id\u003e\n            \u003cphase\u003egenerate-sources\u003c/phase\u003e\n            \u003cgoals\u003e\n                \u003cgoal\u003egenerate\u003c/goal\u003e\n            \u003c/goals\u003e\n            \u003cconfiguration\u003e\n                \u003cgeneratorName\u003ekotlin\u003c/generatorName\u003e \u003c!-- options: kotlin, java - default kotlin --\u003e\n                \u003cinputFile\u003epath/to/my/asyncapi_specification.yaml\u003c/inputFile\u003e\n                \u003cmodelPackage\u003emy.package.path.model\u003c/modelPackage\u003e \u003c!-- package name for data class/POJO --\u003e\n                \u003cclientPackage\u003emy.package.path.client\u003c/clientPackage\u003e \u003c!-- package name for kafka client - default modelPackage--\u003e\n                \u003cschemaPackage\u003emy.package.path.schema\u003c/schemaPackage\u003e \u003c!-- package name for avro schema - default modePackage --\u003e\n                \u003cconfiguration\u003e\n                    \u003cgenerateModels\u003etrue\u003c/generateModels\u003e \u003c!-- can skip models - default is true --\u003e\n                    \u003cgenerateSpringKafkaClient\u003etrue\u003c/generateSpringKafkaClient\u003e \u003c!-- default is false --\u003e\n                    \u003cgenerateAvroSchema\u003etrue\u003c/generateAvroSchema\u003e \u003c!-- default is false --\u003e\n                \u003c/configuration\u003e\n            \u003c/configuration\u003e\n        \u003c/execution\u003e\n    \u003c/executions\u003e\n\u003c/plugin\u003e\n```\n\n### Spring Kafka Clients\n\nFor the spring kafka clients, we generate the Producer and Consumer depending on the operation that the event message has in the specification.\nIf not operation is specified, we generate both. \n\n#### Producer\n\nA spring kafka producer is generated by the 'ChannelName' as the producer, with 'Producer' as a suffix.\n\nExample:\n```yaml\nchannels:\n  customerUpdated:\n    address: customer.updated.v1\n    messages:\n      customerRead:\n        $ref: '#/components/messages/customerReadPayload'\n    description: My description\n```\n\nThis yaml will generate a `CustomerUpdatedProducer` class, that accepts as payload, a 'message' `customerReadPayload`. It can looks something like,\n\n```kotlin\n/**\n * Producer for topic 'customer.updated.v1'\n */\n@Component\nclass CustomerUpdatedProducer(\n    private val kafkaTemplate: KafkaTemplate\u003cString, Any\u003e\n) {\n    private val log = LoggerFactory.getLogger(CustomerUpdatedProducer::class.java)\n\n    fun sendCustomerReadPayload(key: String, message: CustomerReadPayload) {\n        log.info(\"Sending CustomerReadPayload to topic=customer.updated.v1, key={}\", key)\n        kafkaTemplate.send(ProducerRecord(\"customer.updated.v1\", key, message))\n    }\n}\n```\n\nAnd this class can be injected into the application service class, and used.\n\n#### Consumer\n\nA spring kafka consumer is a bit different. Here, we will generate a `KafkaListener` which the application does not have to 'run' anywhere, it\nwill simply pick up event message from the specified topic. The consumer will generate to entities,\n\n- A interface with suffix 'Handler'\n- A class that inject said interface 'Handler' and has a 'listen' method\n\nExample:\n```yaml\nchannels:\n  customerContactInfoUpdate:\n    address: customer.contact-info-update.v1\n    # This channel handles messages of two different types of message\n    messages:\n      updateEmail:\n        $ref: '#/components/messages/updateEmailPayload'\n      updatePhoneNumber:\n        $ref: '#/components/messages/updatePhoneNumberPayload'\n    description: My deacription\n```\n\nThis yaml will generate an interface `CustomerContactInfoUpdateHandler` and `CustomerContactIntoUpdateListener`, which will look something like,\n\n```kotlin\n/**\n * Handler for messages on topic 'customer.contact-info-update.v1'\n */\ninterface CustomerContactInfoUpdateHandler {\n    fun onCustomerEmailPayload(message: KafkaMessage\u003cCustomerEmailPayload\u003e)\n    fun onCustomerPhoneNumberPayload(message: KafkaMessage\u003cCustomerPhoneNumberPayload\u003e)\n}\n```\n\nand\n\n```kotlin\n/**\n * Spring Kafka Listener for topic 'customer.contact-info-update.v1'\n */\n@Component\n@ConditionalOnBean(CustomerContactInfoUpdateHandler::class)\nclass CustomerContactInfoUpdateListener(\n    private val handler: CustomerContactInfoUpdateHandler\n) {\n\n    private val log = LoggerFactory.getLogger(CustomerContactInfoUpdateListener::class.java)\n\n    @KafkaListener(topics = [\"customer.contact-info-update.v1\"], groupId = \"\\${spring.kafka.consumer.group-id}\")\n    fun listen(record: ConsumerRecord\u003cString, Any\u003e) {\n        val payload = record.value()\n\n        // Convert headers to Map\u003cString, Any\u003e\n        val headers = record.headers().associate { it.key() to String(it.value()) }\n\n        when (payload) {\n            is CustomerEmailPayload -\u003e {\n                log.debug(\"Dispatching CustomerEmailPayload from topic customer.contact-info-update.v1\")\n\n                // Wrap in KafkaMessage\n                val message = KafkaMessage(\n                    payload = payload,\n                    key = record.key(),\n                    headers = headers,\n                    topic = record.topic(),\n                    partition = record.partition(),\n                    offset = record.offset(),\n                    timestamp = record.timestamp()\n                )\n\n                handler.onCustomerEmailPayload(message)\n            }\n            is CustomerPhoneNumberPayload -\u003e {\n                log.debug(\"Dispatching CustomerPhoneNumberPayload from topic customer.contact-info-update.v1\")\n\n                // Wrap in KafkaMessage\n                val message = KafkaMessage(\n                    payload = payload,\n                    key = record.key(),\n                    headers = headers,\n                    topic = record.topic(),\n                    partition = record.partition(),\n                    offset = record.offset(),\n                    timestamp = record.timestamp()\n                )\n\n                handler.onCustomerPhoneNumberPayload(message)\n            }\n            else -\u003e {\n                log.warn(\"Received unknown message type on topic customer.contact-info-update.v1: {}\", payload::class.java.name)\n            }\n        }\n    }\n}\n```\n\nThe way this can be used, is through a service in the application that implements the 'Handler' interface, and is able to do something with the received message.\n\nExample:\n```kotlin\n@Service\nclass CustomerUpdatedService : CustomerUpdatedHandler {\n\n    private val log = log()\n\n    override fun onCustomerReadPayload(message: KafkaMessage\u003cCustomerReadPayload\u003e) {\n        log.info(\"Worked, received customer update message: {}\", message)\n    }\n}\n```\n\nOne of the reasons this is the implementation, is that we needed a way to 'activate' the listener. There can be use-cases where you inherit some generated code from\na AsyncAPI specification, but are only interested in parts of it. If we would generate the `KafkaListener` directly, it could create false positive and metrics because\nthe application would be receive the messages and doing anything with them. By having this 'implement interface' step, we avoid this.\n\n## Features supported\n\n### Parser\n\nThe core parsing logic is stable and handles the structural validation of AsyncAPI documents.\n\n- [x] **AsyncAPI YAML Support:** Reads and Parses yaml format.\n- [ ] **AsyncAPI JSON Support:** Reads and Parses yaml format.\n- [x] **Context-Aware Error Handling:** Provides precise error messages with line numbers and JSON paths.\n- [x] **Reference Resolution:** Supports internal and external file references.\n- [x] **Components:** Full parsing support for Schemas, Messages, Channels, Parameters, etc.\n\n### Schema Formats\n\n- [x] **Yaml Schema:** Fully supported (default format).\n- [ ] **Multi-Format Schemas:**\n  - [ ] **JSON Schema:** Support for parsing JSON schemas defined in AsyncAPI documents.\n  - [ ] **Avro Schema:** Support for parsing Avro schemas defined in AsyncAPI documents.\n  - [ ] **Protobuf Schema:** Support for parsing Protobuf schemas defined in AsyncAPI documents.\n  - [ ] **RAML Schema:** Support for parsing Protobuf schemas defined in AsyncAPI documents.\n\n### Validator\n\n- [x] **Structural Validation:** Ensures the AsyncAPI document adheres to the AsyncAPI specification.\n- [x] **Context-Aware Error Handling:** Provides precise error messages with line numbers and context.\n- [x] **Warnings:** Provides warnings for best practices and potential issues.\n- [ ] **Formatted Warnings:** Enhanced warning messages with suggestions for improvement.\n\n## Future plans\n\n- [ ] **Stable Release:** Move from BETA to stable release with comprehensive testing.\n- [ ] **CLI Tool:** Publish the already made CLI module to package managers like brew and dnf.\n- [ ] **Documentation:** Complete documentation with examples and guides.\n- [ ] **Additional Generators:** Expand support for more programming languages and frameworks, i.e., Quarkus Kafka.\n- [ ] **Enhanced Schema Support:** Full support for multi-format schemas including Avro and Protobuf.\n- [ ] **Serialization:** Consider using kotlinx-serialization for writing bundled schemas to files.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevryfs%2Fasyncapi-generator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevryfs%2Fasyncapi-generator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevryfs%2Fasyncapi-generator/lists"}