{"id":22230128,"url":"https://github.com/sngular/scs-multiapi-plugin","last_synced_at":"2025-07-27T19:32:21.548Z","repository":{"id":36951432,"uuid":"494445816","full_name":"sngular/scs-multiapi-plugin","owner":"sngular","description":"This is a Maven plugin designed to help developers automatizing the creation of code classes from YML files based on AsyncApi and OpenAPI.","archived":false,"fork":false,"pushed_at":"2024-04-01T10:58:31.000Z","size":3341,"stargazers_count":46,"open_issues_count":24,"forks_count":9,"subscribers_count":9,"default_branch":"main","last_synced_at":"2024-04-02T09:24:11.862Z","etag":null,"topics":["asyncapi","asyncapi-generator","asyncapi-specification","asyncapi-tooling","openapi","openapi-codegen","openapi-generator","spring","spring-boot"],"latest_commit_sha":null,"homepage":"http://sngular.com","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sngular.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}},"created_at":"2022-05-20T11:56:39.000Z","updated_at":"2024-04-23T12:03:52.797Z","dependencies_parsed_at":"2023-12-14T09:28:04.788Z","dependency_job_id":"bee65cf1-ebd5-4456-88a4-1ca01fd0f44d","html_url":"https://github.com/sngular/scs-multiapi-plugin","commit_stats":null,"previous_names":[],"tags_count":134,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sngular%2Fscs-multiapi-plugin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sngular%2Fscs-multiapi-plugin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sngular%2Fscs-multiapi-plugin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sngular%2Fscs-multiapi-plugin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sngular","download_url":"https://codeload.github.com/sngular/scs-multiapi-plugin/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227831079,"owners_count":17826155,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["asyncapi","asyncapi-generator","asyncapi-specification","asyncapi-tooling","openapi","openapi-codegen","openapi-generator","spring","spring-boot"],"created_at":"2024-12-03T01:14:22.816Z","updated_at":"2024-12-03T01:14:27.839Z","avatar_url":"https://github.com/sngular.png","language":"Java","readme":"# SCS MultiApi Plugin\n\n[![Codacy Badge](https://app.codacy.com/project/badge/Grade/4a9be5a4b6ab48afba293b2315edd47e)](https://app.codacy.com/gh/sngular/scs-multiapi-plugin/dashboard?utm_source=gh\u0026utm_medium=referral\u0026utm_content=\u0026utm_campaign=Badge_grade)[![Maven Central](https://img.shields.io/maven-central/v/com.sngular/scs-multiapi-maven-plugin.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22com.sngular%22%20AND%20a:%22scs-multiapi-maven-plugin%22)\n\nThis is a plugin designed to help developers automatizing the creation of\ncode classes from YML files based on AsyncApi and OpenAPI. It is presented in 2 flavours\nMaven and Gradle\n\n## Index\n\n- [SCS MultiApi Plugin](#scs-multiapi-plugin)\n- [Index](#index)\n- [Main Configuration](#main-configuration)\n  - [How to configure the POM file](#how-to-configure-the-pom-file)\n  - [How to configure the build.gradle file](#how-to-configure-the-build-file)\n- [AsyncApi Generator](#asyncapi-generator)\n  - [Configuration](#configuration)\n    - [Generated Sources Folder](#generated-sources-folder)\n  - [How is apiPackage set?](#how-is-apipackage-set)\n  - [How is modelPackage set?](#how-is-modelpackage-set)\n  - [Class Generation](#class-generation)\n    - [Consumer and Supplier classes](#consumer-and-supplier-classes)\n      - [Method interfaces](#method-interfaces)\n      - [Mapper](#mapper)\n        - [Implementation](#implementation)\n      - [Stream Bridge class](#stream-bridge-class)\n- [OpenApi Generator](#openapi-generator)\n  - [Getting Started](#getting-started)\n  - [Initial Considerations](#initial-considerations)\n  - [Usage](#usage)\n- [Property Validation](#property-validation)\n\n## Main Configuration\n\nThis plugin allows developers to automatize the creation of code classes for\nREST and Kafka connections, based on YML files under the AsyncApi and OpenApi\nspecifications. In the latter case, many of the configuration options and classes\nthat are generated are based on reimplementation or modification of the OpenAPI Generator\nmodels and template designs.\n\nThe generation of the REST and Kafka connections is independent each other and\ncould be used only one, or both at the same time.\n\nHere is the documentation for these technologies:\n\n- [OpenApi](https://swagger.io/specification/)\n- [AsyncApi](https://www.asyncapi.com/docs/getting-started)\n- [OpenAPI Generator](https://openapi-generator.tech/docs/configuration)\n\n### How to configure the POM file\n\nTo maintain the generation of the different types of classes independent, they\nare configured as two different goals on the plugin, `asyncapi-generation` and\n`openapi-generation`.\nAs commented above, they both could be used at the same time, setting a double\n*execution* for the plugin in the `pom.xml` file.\n\n```xml\n\n\u003cplugin\u003e\n  \u003cgroupId\u003ecom.sngular\u003c/groupId\u003e\n  \u003cartifactId\u003escs-multiapi-maven-plugin\u003c/artifactId\u003e\n  \u003cversion\u003e5.4.3\u003c/version\u003e\n  \u003cexecutions\u003e\n    \u003cexecution\u003e\n      \u003cid\u003easyncapi\u003c/id\u003e\n      \u003cphase\u003egenerate-sources\u003c/phase\u003e\n      \u003cgoals\u003e\n        \u003cgoal\u003easyncapi-generation\u003c/goal\u003e\n      \u003c/goals\u003e\n      \u003cconfiguration\u003e\n        \u003cspecFiles\u003e\n          ...\n        \u003c/specFiles\u003e\n      \u003c/configuration\u003e\n    \u003c/execution\u003e\n\n    \u003cexecution\u003e\n      \u003cid\u003eopenapi\u003c/id\u003e\n      \u003cphase\u003egenerate-sources\u003c/phase\u003e\n      \u003cgoals\u003e\n        \u003cgoal\u003eopenapi-generation\u003c/goal\u003e\n      \u003c/goals\u003e\n      \u003cconfiguration\u003e\n        \u003cspecFiles\u003e\n          \u003cspecFile\u003e\n            ...\n          \u003c/specFile\u003e\n        \u003c/specFiles\u003e\n      \u003c/configuration\u003e\n    \u003c/execution\u003e\n  \u003c/executions\u003e\n\u003c/plugin\u003e\n```\n\nIn the example above, you can see a partial configuration for the plugin with\na double *execution*. This makes necessary to set an `id` for each execution,\n`asyncapi` and `openapi` in this case.\n\nIn the case that you only want to run one of the goals of the plugin, you only\nneed to remove the *execution* section that you don't need.\n\nIn the [AsyncApi Generator](#asyncapi-generator) and the\n[OpenApi Generator](#openapi-generator) sections, you can find more information\nabout how they work, and the parameters and configuration options they offer.\n\n#### Mandatory dependencies\n\nThese dependencies are used by generated code\n\n```xml\n \u003cdependencies\u003e\n       \u003cdependency\u003e\n            \u003cgroupId\u003eio.swagger.parser.v3\u003c/groupId\u003e\n            \u003cartifactId\u003eswagger-parser-core\u003c/artifactId\u003e\n            \u003cversion\u003e2.1.20\u003c/version\u003e\n        \u003c/dependency\u003e\n        \n        \u003cdependency\u003e\n            \u003cgroupId\u003eio.swagger.core.v3\u003c/groupId\u003e\n            \u003cartifactId\u003eswagger-annotations-jakarta\u003c/artifactId\u003e\n            \u003cversion\u003e2.2.20\u003c/version\u003e\n        \u003c/dependency\u003e\n        \n        \u003cdependency\u003e\n            \u003cgroupId\u003ejakarta.validation\u003c/groupId\u003e\n            \u003cartifactId\u003ejakarta.validation-api\u003c/artifactId\u003e\n            \u003cversion\u003e3.0.2\u003c/version\u003e\n        \u003c/dependency\u003e\n \u003c/dependencies\u003e\n```\n\n### How to configure the build file\n\nTo maintain the generation of the different types of classes independent, they\nare configured as two different task on the plugin, `openApiTask` and\n`asyncApiTask`.\nApply the plugin in the `build.gradle` file and invoke the task.\n\n```groovy\nplugins {\n  id \"java\"\n  id \"com.sngular.scs-multiapi-gradle-plugin' version '5.4.3\"\n\n  openapimodel {\n\n  }\n\n  asyncapimodel {\n\n  }\n}\n```\n\nIn the example above, you can see a partial configuration for the plugin with\nthe extension configuration. Just create the (openapi|asyncapi)model objets to\nconfigure the tasks.\n\nIn the case that you only want to run one of the goals of the plugin, you only\nneed to remove the *execution* section that you don't need.\n\nIn case no configuration is provided but only the file to generate an exception will be raised and an error will occur.\nIn the [AsyncApi Generator](#asyncapi-generator) and the\n[OpenApi Generator](#openapi-generator) sections, you can find more information\nabout how they work, and the parameters and configuration options they offer.\n\n#### Mandatory gradle dependencies\n\nThese dependencies are used by generated code\n\n``` gradle\nimplementation 'io.swagger.parser.v3:swagger-parser-core:2.1.20'\nimplementation 'io.swagger.core.v3:swagger-annotations-jakarta:2.2.20'\nimplementation 'jakarta.validation:jakarta.validation-api:3.0.2'\n```\n\n## AsyncApi Generator\n\n### Configuration\n\n#### Maven\n\nThe plugin defined `phase` and `goal` parameters are expected to be\n*generate-sources* and *asyncapi-generation*, as they are the only values for\nwhich the plugin is designed.\n\n```xml\n\n\u003cplugin\u003e\n  \u003cgroupId\u003ecom.sngular\u003c/groupId\u003e\n  \u003cartifactId\u003escs-multiapi-maven-plugin\u003c/artifactId\u003e\n  \u003cversion\u003e5.4.3\u003c/version\u003e\n  \u003cexecutions\u003e\n    \u003cexecution\u003e\n      \u003cphase\u003egenerate-sources\u003c/phase\u003e\n      \u003cgoals\u003e\n        \u003cgoal\u003easyncapi-generation\u003c/goal\u003e\n      \u003c/goals\u003e\n      \u003cconfiguration\u003e\n        \u003cspecFiles\u003e\n          \u003cspecFile\u003e\n            \u003cfilePath\u003ePATH_TO_YML\u003c/filePath\u003e\n          \u003c/specFile\u003e\n          \u003cspecFile\u003e\n            \u003cfilePath\u003ePATH_TO_YML\u003c/filePath\u003e\n            \u003cconsumer\u003e\n              \u003cids\u003epublishOperation\u003c/ids\u003e\n              \u003cclassNamePostfix\u003eMY_CONSUMER_CLASS\u003c/classNamePostfix\u003e\n              \u003cmodelNameSuffix\u003eDTO\u003c/modelNameSuffix\u003e\n              \u003capiPackage\u003ecom.sngular.apigenerator.asyncapi.business_model.model.event.consumer\u003c/apiPackage\u003e\n              \u003cmodelPackage\u003ecom.sngular.apigenerator.asyncapi.business_model.model.event\u003c/modelPackage\u003e\n            \u003c/consumer\u003e\n            \u003csupplier\u003e\n              \u003cids\u003esubscribeOperation\u003c/ids\u003e\n              \u003capiPackage\u003ecom.sngular.apigenerator.asyncapi.business_model.model.event.producer\u003c/apiPackage\u003e\n              \u003cmodelPackage\u003ecom.sngular.apigenerator.asyncapi.business_model.model.event\u003c/modelPackage\u003e\n            \u003c/supplier\u003e\n          \u003c/specFile\u003e\n        \u003c/specFiles\u003e\n        \u003cgeneratedSourcesFolder\u003esources-generated\u003c/generatedSourcesFolder\u003e\n      \u003c/configuration\u003e\n    \u003c/execution\u003e\n  \u003c/executions\u003e\n\u003c/plugin\u003e\n```\n\n#### Gradle\n\nIn this case we have an extension model to fulfill. Similar to the Maven one.\n\n```groovy\nopenapimodel {\n  specFile {\n    {\n      filePath = './src/main/resources/api/rest/api-rest.yml'\n      apiPackage = 'com.sngular.world_domination.api'\n      modelPackage = 'com.sngular.world_domination.model'\n      useTagsGroup = true\n    }\n    overWriteModel = true\n  }\n}\n```\n\nAs you can see in the example above, there is a main parameter **specFiles**\nthat receives a list of **specFile** attributes groups, so you can set as many\nYML files as you want.\n\n**specFiles** could be configured in two different ways:\n\n1. The first one is to configure only the YML file. This is made using the\n   **filePath** parameter, that expects to receive the path to the file. Using\n   the plugin in this way, you can't configure the model package or the api\n   package in the pom file, neither other options, so they will be configured as\n   its explained in [apiPackage](#how-is-apipackage-set) and\n   [modelPackage](#how-is-modelpackage-set) sections.  \n   This way it's limited to the usage of Consumer and Supplier methods.\n\n    ```xml\n    \u003cspecFile\u003e\n        \u003cfilePath\u003ePATH_TO_YML\u003c/filePath\u003e\n    \u003c/specFile\u003e\n    ```\n\n2. The second one is to configure the YML file with the consumers, supplier\n   producers and streamBrige producers that you want to generate.\n\n  ```xml\n\n\u003cspecFile\u003e\n  \u003cfilePath\u003ePATH_TO_YML\u003c/filePath\u003e\n  \u003cconsumer\u003e\n    \u003cids\u003epublishOperation\u003c/ids\u003e\n    \u003cclassNamePostfix\u003eMY_CONSUMER_CLASS\u003c/classNamePostfix\u003e\n    \u003cmodelNameSuffix\u003eDTO\u003c/modelNameSuffix\u003e\n    \u003capiPackage\u003ecom.sngular.apigenerator.asyncapi.business_model.model.event.consumer\u003c/apiPackage\u003e\n    \u003cmodelPackage\u003ecom.sngular.apigenerator.asyncapi.business_model.model.event\u003c/modelPackage\u003e\n  \u003c/consumer\u003e\n  \u003csupplier\u003e\n    \u003cids\u003esubscribeOperation\u003c/ids\u003e\n    \u003capiPackage\u003ecom.sngular.apigenerator.asyncapi.business_model.model.event.producer\u003c/apiPackage\u003e\n    \u003cmodelPackage\u003ecom.sngular.apigenerator.asyncapi.business_model.model.event\u003c/modelPackage\u003e\n  \u003c/supplier\u003e\n  \u003cstreamBridge\u003e\n    \u003cids\u003estreamBridgeOperation\u003c/ids\u003e\n    \u003capiPackage\u003ecom.sngular.apigenerator.asyncapi.business_model.model.event.producer\u003c/apiPackage\u003e\n    \u003cmodelPackage\u003ecom.sngular.apigenerator.asyncapi.business_model.model.event\u003c/modelPackage\u003e\n  \u003c/streamBridge\u003e\n\u003c/specFile\u003e\n  ```\n\n  ```groovy\n  specFile {\n  {\n    filePath = './src/main/resources/api/event/event-api.yml'\n    consumer {\n      ids = 'publishOperation'\n      apiPackage = 'com.sngular.apigenerator.asyncapi.business_model.model.event.consumer'\n      modelPackage = 'com.sngular.apigenerator.asyncapi.business_model.model.event'\n    }\n    supplier {\n      ids = 'subscribeOperation'\n      apiPackage = 'com.sngular.apigenerator.asyncapi.business_model.model.event.producer'\n      modelPackage = 'com.sngular.apigenerator.asyncapi.business_model.model.event'\n    }\n    streamBridge {\n      ids = 'streamBridgeOperation'\n      apiPackage = 'com.sngular.apigenerator.asyncapi.business_model.model.event.producer'\n      modelPackage = 'com.sngular.apigenerator.asyncapi.business_model.model.event'\n    }\n  }\n  overWriteModel = true\n}\n  ```\n\nAs you can see in the example above, there are three blocks of parameters that\ncan be configured in the plugin.\n\n- **filePath**: This parameter works in the same way as in the first option.\n- **consumer**, **supplier** and **streamBridge**: They are both configured in\n  the same way and can receive the same parameters. These parameters are:\n  - **ids**: With this parameter you can set the operationId that you want to\n      be generated as subscriber or publisher. If this parameter is not defined for\n      the `consumer` section, all the subscribe operations defined in the YML file,\n      will be generated. If only one of `supplier` and `streamBridge` sections are\n      defined, and this parameter is not defined inside it, all the publish\n      operations defined in the YML file will be generated. If both `supplier` and\n      `streamBridge` sections are defined, it`s needed to define which operations\n      belong to each category.\n  - **classNamePostfix**: This parameter receives the name of the class that\n      it's going to be generated containing the Beans. This parameter is optional,\n      and by default the classes will be called `Producer`, `StreamBridgeProducer`\n      and `Subscriber`.\n  - **modelNameSuffix**: With this parameter you can set the suffix that is\n      going to be used in the entities of the generated classes. For example if\n      you set this to `DTO`, and there is a class named `EntityClass`, it will\n      result as `EntityClassDTO`. This parameter is optional.\n  - **apiPackage**: This parameter receive a package name, where the\n      generated classes will be generated. This parameter is optional.\n      Check [how is the apiPackage set](#how-is-apipackage-set) for\n      more information about how this parameter works, and the values it\n      could have.\n  - **modelPackage**: This parameter receives a package name, where the entities\n      used for the generated classes are defined. As it's explained in the\n      [Mapper Section](#mapper), those entities are usually auto-generated, so the\n      plugin expects the modelPackage to be the package where them are included.\n      **Note that the plugin doesn't create the entities neither checks their\n      existence**, it takes their names from the YML file and assume that they are\n      created by the user. As the previous parameter, this is also optional.\n      Check [how is the modelPackage set](#how-is-modelpackage-set) for more\n      information about how his parameter works, and the values it could have.\n  -  **dateFormat**: This parameter changes the format annotation for `LocalDate` fields.\n      The syntax follow the [Java SimpleDateFormat](https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html).\n      The default value are `yyyy-MM-dd`.\n  -  **dateTimeFormat**: This parameter changes the format annotation for `LocalDateTime`\n      fields. The syntax follow the [Java SimpleDateFormat](https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html).\n      The default value are `yyyy-MM-dd'T'HH:mm:ss`.\n  -  **useTimeType**: Enum TimeType value. Controls the types used when generating dates. Can be `LOCAL` or `ZOINED`.\n      The default value is `TimeType.LOCAL`. \n\nThe configuration of `consumer`, `supplier` and `streamBridge` are independent.\nIf only one of them is configured in the pom file, only that one will be\ngenerated.\n\n#### Generated Sources Folder\n\nThere is also an independent parameter that affects to all the *specFiles*\ngenerated, which is called **generatedSourcesFolder**. This parameter expects\nto receive a string, that could include letters, numbers and `-`, with the\nname of the folder where generated sources by the plugin will be located.\n\nBy default, it's values is `generated-sources`, so the files will be in\n`.../target/generated-sources/apigenerator/...`. If you set another value in\nthe pom.xml file, as in the example above, files will remain in\n`.../target/sources-generated/apigenerator/...`.\n\n### How is apiPackage set?\n\nThe api package could be set in three different ways.\n\n- **User definition**: The user provides a package name using the parameter in\n  the pom.xml file.\n- **GroupID from YML**: If the user doesn't provide a package name, the plugin\n  will try to use the `groupId` attribute from the YML file that is in use.\n- **Default package name**: If neither of the previous options were given, the\n  plugin will use a default package name, that is stablished as\n  `com.sngular.apigenerator.asyncapi`.\n\n### How is modelPackage set?\n\nThe model package could be set in four different ways.\n\n- **User definition**: The user provides a package name using the parameter in\n  the pom.xml file.\n- **Namespace from YML**: If the user doesn't provide a package name, the\n  plugin will check if the entity name definition in the YML file, includes a\n  complete package name.\n\n```yaml\norder/createCommand:\n  subscribe:\n    operationId: \"subscribeOperation\"\n    message:\n      $ref: '#/components/messages/com.sngular.apigenerator.asyncapi.model.CreateOrder'\n```\n\n- **Namespace from Avro**: The plugin will check for a `namespace`\n  attribute defined in the Avro file and use it, if a namespace is\n  not defined it will throw an exception. The plugin expects to receive\n  a relative path from the `yml` file folder.\n\n```yaml\norder/created:\n  publish:\n    operationId: \"publishOperation\"\n    message:\n      $ref: 'path_to_Avro_file'\n```\n\n- **Default package name**: If neither of the previous options were given, the\n  plugin will use a default package name, that is stablished as\n  `com.sngular.apigenerator.asyncapi.model`.\n\n### Class Generation\n\n#### Consumer and Supplier classes\n\nThose are a pair of classes, separated by the directionality of the messages.\nThey came from the plugin fully implemented by making reference to the\ninterfaces of the next section. Their names could be modified using the\n`classNamePostfix` parameter specified on the\n[Usage section](#usage), being by default **Producer** and\n**Subscriber**.\n\n```java\n\n@Configuration\npublic class StreamTopicListenerConsumer {\n\n  private final ISubscribeOperation subscribeOperation;\n\n  protected StreamTopicListenerConsumer(final ISubscribeOperation subscribeOperation) {\n    this.subscribeOperation = subscribeOperation;\n  }\n\n  @Bean\n  public Consumer\u003cCreateOrder\u003e consumerSubscribeOperation() {\n    return value -\u003e subscribeOperation.subscribeOperation(value);\n  }\n}\n```\n\nThis sample class, is related to the previously used YML file, and in it, you\ncould see that it came fully implemented, based on the related Interface that\nlets the personalization and implementation to the user. Also, in this example\nis possible to see how the YML attribute 'operationId' is used to name the\nmethods as `Consumer'OperationId'` or `Publisher'OperationId'`.\n\n##### Method interfaces\n\nThose are a group of interfaces that are related to the previous seen classes.\nThere are as many as operations are defined in the YML file, and in the\nprevious classes, so there is only one operation defined in each interface.\n\nThis layer is the only one that needs work by the end user, so it needs to\nimplement these interfaces.\n\nThese interfaces are named following the \"I*OperationId*\" pattern, where\n'OperationId' comes from the YML file definition of the channels section.\nThe method is named as 'OperationId' as well as on the classes in the\nabove section.\n\n```java\npublic interface ISubscribeOperation {\n\n  void subscribeOperation(CreateOrder value);\n}\n```\n\n#### Bindings\n\nAsyncapi support a way to specify specific configuration for certain protocols.\n\nNowadays, we only support Kafka specific information to define a Key form.\n\nMessages as you can find\n[here](\u003chttps://github.com/asyncapi/bindings/blob/master/kafka/README.md\u003e).\n\nWhen a binding is specified in a message we will generate a generic class\nnamed as MessageWrapper which will contain the payload and the key\nused in to build a Message.\nYou will find such class by each api package you define.\n\n##### Mapper\n\nThe entities used for the definitions both on the previous seen classes and\nthis interfaces, are auto-generated entities, based on the same YML file.\nBecause of that, they need to be mapped to a user defined entity using a mapper\nutility class.\n\nThis mapper must be defined by the user on its own way to improve the\npersonalization capabilities of the plugin.\n\nDown here you have an example of the mapper utility class as well as a simple\nclass implementing the interface defined above.\n\n```java\n\n@Mapper\npublic interface Mapper {\n\n  Order map(com.sngular.apigenerator.asyncapi.business_model.model.event.Order value);\n}\n```\n\n###### Implementation\n\n```java\n\n@Component\npublic class SubscribeOperation implements ISubscribeOperation {\n\n  private final Mapper mapper;\n\n  public subscribeOperation(final Mapper mapper) {this.mapper = mapper;}\n\n  @Override\n  public void subscribeOperation(final Order value) {\n    com.sngular.apigenerator.asyncapi.business_model.model.Order orderMapped = mapper.map(value);\n    //TODO: implement the functionality\n  }\n}\n```\n\n#### Stream Bridge class\n\nIn this case, there is only one class where all the selected operations will be\nincluded. It's name could be modified using the `classNamePostfix` parameter\nspecified on the [Usage section](#usage), being by default\n**StreamBridgeProducer**.\n\n```java\n\n@Configuration\npublic class StreamBridgeProducer {\n\n  private StreamBridge streamBridge;\n\n  public void streamBridgeOperation(CreateOrder createOrder) {\n    streamBridge.send(\"publishOperation\", createOrder);\n  }\n}\n```\n\nThis sample class, is related to the previosly used YML file, and in it you\ncould see that it came fully implemented.\n\nAlso, it's important to note that using Stream Bridge, the *binding* where the\nmessages are going to be sent is included in the auto generated class. This is\ndefined by the application properties using `function`, `binders` and\n`bindings`, as in the next example:\n\n```yaml\nspring:\n  kafka:\n    bootstrap-servers: localhost:xxxx\n    producer:\n      client-id: peter\n      key-serializer: org.apache.kafka.common.serialization.StringSerializer\n      value-serializer: org.springframework.kafka.support.serializer.JsonSerializer\n  cloud:\n    function:\n      definition: publishOperation\n    stream:\n      defaultBinder: kafka\n      bindings:\n        publishOperation:\n          destination: orderCreated\n      binders:\n        kafka:\n          defaultCandidate: true\n          type: kafka\n          producer-properties:\n            key.serializer: org.apache.kafka.common.serialization.StringSerializer\n            value.serializer: org.springframework.kafka.support.serializer.JsonSerializer\n```\n\nBecause the plugin cannot access the application properties, the name of the\ncorresponding *binding* must be used as the **channel identifier** in the YML\nfile that's set on the plugin configuration, as you can see on the next\nextract:\n\n```yaml\nchannels:\n  publishOperation:\n    subscribe:\n      operationId: \"streamBridgeOperation\"\n      message:\n        $ref: '#/components/messages/CreateOrder'\n```\n\nDue to the limitations on topics naming, the identifier of the channels that\nare going to be used as Stream Bridge publishers, **only could include `-` or\n`.` as separators**, slash `/` is not allowed.\n\n## OpenApi Generator\n\n### Getting Started\n\nIn order to get this plugin working, you need the following things installed\nin your computer:\n\n- Java 11 Version\n- Maven\n\nDepending on the approach with which you are going to use the plugin, other\ndependencies will be necessary, for example:\n\n- spring-boot-starter-webflux, in case you want to implement an API with\n  responses in Mono/Flux Reactor types or use them for external calls through\n  Spring WebClient.\n\nAfter you have these installed, you need to add this plugin in your pom.xml or build.gradle\nfile. Here is an example of a basic configuration:\n\n```xml\n\n\u003cplugin\u003e\n  \u003cgroupId\u003ecom.sngular\u003c/groupId\u003e\n  \u003cartifactId\u003escs-multiapi-maven-plugin\u003c/artifactId\u003e\n  \u003cversion\u003e5.4.3\u003c/version\u003e\n  \u003cexecutions\u003e\n    \u003cexecution\u003e\n      \u003cgoals\u003e\n        \u003cgoal\u003eopenapi-generation\u003c/goal\u003e\n      \u003c/goals\u003e\n      \u003cconfiguration\u003e\n        \u003cspecFiles\u003e\n          \u003cspecFile\u003e\n            \u003cfilePath\u003e${project.basedir}/src/main/resources/api/api.yml\u003c/filePath\u003e\n            \u003capiPackage\u003ecom.sngular.apigenerator.openapi.api\u003c/apiPackage\u003e\n            \u003cmodelPackage\u003ecom.sngular.apigenerator.openapi.api.model\u003c/modelPackage\u003e\n            \u003cmodelNameSuffix\u003eDTO\u003c/modelNameSuffix\u003e\n          \u003c/specFile\u003e\n        \u003c/specFiles\u003e\n      \u003c/configuration\u003e\n    \u003c/execution\u003e\n  \u003c/executions\u003e\n\u003c/plugin\u003e\n```\n\n```groovy\nopenapimodel {\n  specFile {\n    {\n      filePath = './src/main/resources/api/api.yml'\n      apiPackage = 'com.sngular.apigenerator.openapi.api'\n      modelPackage = 'com.sngular.apigenerator.openapi.api.model'\n      useTagsGroup = true\n    }\n    overWriteModel = true\n  }\n}\n```\n\n### Initial Considerations\n\nBefore using this plugin we have to warn that not all the complexity and\nsupport offered by the use of swagger.io yml files is supported.\n\nSince 1.1.0 version, we support the definition of parameters in both Path\nand Operation object. ❗❗❗ Please bear in mind that we use the Option\nresolver from OpenApi which will override the Operation parameters\nif you have a parameter defined in the Path.\n\nWe establish here some of these options that are not yet supported and that\nwill be added to this plugin as time goes by and the existing need among users.\n\n- Using Multiple Authentication Types within the security options both at an\n  operational and general level.\n\n- The use of OAuth 2 and OpenID Connect Discovery Authentication Types.\n\n### Usage\n\nThis plugin allows us to create multiple apis with just one maven clean\ninstall execution, in this way the user can configure several specFiles tags\nwith different uses, thus generating Apis in the two possible modes: send or\nreceive calls, depending on the options of configuration selected in said\nspecFiles.\n\n```xml\n\n\u003cconfiguration\u003e\n  \u003cspecFiles\u003e\n    \u003cspecFile\u003e\n      \u003cfilePath\u003e${project.basedir}/src/main/resources/api/api.yml\u003c/filePath\u003e\n      \u003capiPackage\u003ecom.sngular.apigenerator.openapi.api\u003c/apiPackage\u003e\n      \u003cmodelPackage\u003ecom.sngular.apigenerator.openapi.api.model\u003c/modelPackage\u003e\n      \u003cmodelNameSuffix\u003eDTO\u003c/modelNameSuffix\u003e\n    \u003c/specFile\u003e\n  \u003c/specFiles\u003e\n\u003c/configuration\u003e\n```\n\n```groovy\nopenapimodel {\n  specFile {\n    {\n      filePath = './src/main/resources/api/api.yml'\n      consumer {\n        apiPackage = 'com.sngular.apigenerator.openapi.api'\n        modelPackage = 'com.sngular.apigenerator.openapi.api.model'\n      }\n      supplier {\n        apiPackage = 'com.sngular.apigenerator.openapi.api'\n        modelPackage = 'com.sngular.apigenerator.openapi.api.model'\n      }\n    }\n    overWriteModel = true\n  }\n}\n```\n\nTo customize these specFiles tags we are going to specify them inside the\nconfiguration tag, we must declare the specFiles tag that contains all files\nthat will be used. Each specFile has their own configuration:\n\n| Name                     | Description                                                                                                                                                                                         | Example                                           |\n|--------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------|\n| filePath                 | Path where the yaml is located                                                                                                                                                                      | ${project.basedir}/src/main/resources/api/api.yml |\n| apiPackage               | Path where the api interface will be located                                                                                                                                                        | com.sngular.apigenerator.openapi                  |\n| modelPackage             | Path where the models will be located                                                                                                                                                               | com.sngular.apigenerator.openapi.model            |\n| modelNamePrefix          | Prefix that will be used ahead of every model´s name                                                                                                                                                | Api                                               |\n| modelNameSuffix          | Suffix that will be used after every model´s name                                                                                                                                                   | DTO                                               |\n| callMode                 | Boolean value to decide if you want to generate the api for external calls. **Use RestClient by default. It´s initialized to false by default**                                                     | false                                             |\n| useTagsGroup             | Boolean value to decide if using tags instead of an URL for group the API. **It´s initialized to false by default**                                                                                 | false                                             |\n| useLombokModelAnnotation | Boolean value to decide if you want your models with Lombok or not   **It´s initialized to false by default**                                                                                       | false                                             |\n| isReactive               | Boolean value to decide if you want to generate the api with responses in Mono/Flux Reactor types. If callmode = true use WebClient instead of RestClient. **It´s initialized to false by default** | false                                             |\n| useTimeType              | Enum TimeType value. Controls the types used when generating dates. Can be local, zoned, or offset. **Initialized to TimeType.LOCAL by default**                                                    | TimeType.OFFSET                                   |\n\nAs the configuration options already indicate, the data model will also be\ncreated within the specified path.This model will be created with the indicated\nprefixes and suffixes and the instances and imports will be made to that model\nwithin the corresponding Api.\n\nThere are two properties configured outside the specFiles, the path where the\nRestClient and the WebClient will be located, if this option is set in any\nof the specFiles, and the name of the folder where the generated sources will\nbe saved in the api of the project.\n\n| Name                                                | Description                                                                                                                                                                                                                                                                     | Example                                 |\n|-----------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------|\n| clientPackage                                       | Path where the RestClient and/or WebClient are located                                                                                                                                                                                                                          | com.sngular.apigenerator.openapi.client |\n| [generatedSourcesFolder](#generated-sources-folder) | Name of the folder, inside `target`, where the files will be located. By defaut it's `generated-sources`                                                                                                                                                                        | generated-sources                       |\n| overwriteModel                                      | Boolean value to decide if you want your models to be overwritten if two or more models have the same name. True means that models will be overwritten and if false is set, it will throw an exception if two models share the same name. It is initialized to false by default | false                                   |\n| springBootVersion                                   | The version of spring to target during generation. It's default value is `2`.                                                                                                                                                                                                   | 3                                       |\n\nWe must clarify that the options to make calls are configured under the\nRestClient or WebClient specifications as indicated above in the configuration\noptions. If several of the APIs to be generated are defined under the same call\noption, a single RestClient/Webclient will be generated for all of them, which\nis initialized with the specific options needed within the class that defines\neach API.\n\n### Usage considerations\n\nThis plugin has been implemented trying to behave like OpenApi Generator Tool,\nbut we decided to change the approach concerning the support of AllOfs, OneOfs\nand AnyOfs.\n\nEvery property that has been indicated in any of these types will be generated\nin the model entity.\n\nThe way the model will behave changes depending on whether it is an AllOf, or\nan AnyOf/OneOf:\n\nIf it is an AllOf, every property referenced will be treated as required\nregardless of which ones are defined in the \"required\" field of the allOf\nstructure.\n\nIf it is an AnyOf or an OneOf, the plugin will only mark as required the\nproperties that have been defined as such in the \"required\" field of these\nstructures. After that, the constructor will check that at least one of the\nproperties will have a value, nothing else, so it is up to the user to fulfill\nthe restrictions he needs for the entity.\n\n**IMPORTANT NOTE**: As previously stated, OneOf and AnyOf will behave the same,\nthis means that OneOf will work the same way as an AnyOf.\n\n## Property validation\n\nBoth AsyncAPI and OpenAPI offer the possibility to add properties and apply constraints\nto the values a certain object can take. To validate these properties,\nwe annotate the pertaining fields and generate the corresponding validators so that the user\ncan later use a framework such as Hibernate to check for correctness.\n\n## Loading specifications from dependencies\n\nThe plugin supports loading API specification YMLs from the classpath. This will be the\nlocation it searches for them in first, falling back to the project directories otherwise.\n\nHere's an example configuration for the maven plugin that loads an AsyncAPI specification\nfrom a local JAR containing `contracts/event-api.yml` in its resources:\n\n```xml\n\u003cplugin\u003e\n  \u003cgroupId\u003ecom.sngular\u003c/groupId\u003e\n  \u003cartifactId\u003escs-multiapi-maven-plugin\u003c/artifactId\u003e\n  \u003cexecutions\u003e\n    \u003cexecution\u003e\n      \u003cid\u003easyncapi\u003c/id\u003e\n      \u003cphase\u003egenerate-sources\u003c/phase\u003e\n      \u003cgoals\u003e\n        \u003cgoal\u003easyncapi-generation\u003c/goal\u003e\n      \u003c/goals\u003e\n      \u003cconfiguration\u003e\n        \u003cspecFiles\u003e\n          \u003cspecFile\u003e\n            \u003cfilePath\u003econtracts/event-api.yml\u003c/filePath\u003e\n          \u003c/specFile\u003e\n        \u003c/specFiles\u003e\n      \u003c/configuration\u003e\n    \u003c/execution\u003e\n  \u003c/executions\u003e\n  \u003cdependencies\u003e\n    \u003cdependency\u003e\n      \u003cgroupId\u003ecom.sngular\u003c/groupId\u003e\n      \u003cartifactId\u003eyml-source\u003c/artifactId\u003e\n      \u003cversion\u003e1.0\u003c/version\u003e\n      \u003cscope\u003esystem\u003c/scope\u003e\n      \u003csystemPath\u003e${project.basedir}/yml-source-1.0.jar\u003c/systemPath\u003e\n    \u003c/dependency\u003e\n  \u003c/dependencies\u003e\n\u003c/plugin\u003e\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsngular%2Fscs-multiapi-plugin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsngular%2Fscs-multiapi-plugin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsngular%2Fscs-multiapi-plugin/lists"}