{"id":21253942,"url":"https://github.com/courseorchestra/hurdy-gurdy","last_synced_at":"2025-10-29T07:38:33.984Z","repository":{"id":37804536,"uuid":"448626169","full_name":"CourseOrchestra/hurdy-gurdy","owner":"CourseOrchestra","description":"Generate client and server side Java/Kotlin code based on OpenAPI spec","archived":false,"fork":false,"pushed_at":"2024-08-26T22:50:47.000Z","size":360,"stargazers_count":34,"open_issues_count":1,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-08-27T01:39:53.813Z","etag":null,"topics":["hurdy-gurdy","openapi","openapi-generator"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CourseOrchestra.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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}},"created_at":"2022-01-16T17:34:56.000Z","updated_at":"2024-08-26T22:50:44.000Z","dependencies_parsed_at":"2023-10-12T05:22:11.487Z","dependency_job_id":"1a735e7c-89da-4174-87f4-521dbeb5f683","html_url":"https://github.com/CourseOrchestra/hurdy-gurdy","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CourseOrchestra%2Fhurdy-gurdy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CourseOrchestra%2Fhurdy-gurdy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CourseOrchestra%2Fhurdy-gurdy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CourseOrchestra%2Fhurdy-gurdy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CourseOrchestra","download_url":"https://codeload.github.com/CourseOrchestra/hurdy-gurdy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225669588,"owners_count":17505386,"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":["hurdy-gurdy","openapi","openapi-generator"],"created_at":"2024-11-21T03:53:33.421Z","updated_at":"2025-10-29T07:38:28.947Z","avatar_url":"https://github.com/CourseOrchestra.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Actions Status: build](https://github.com/courseorchestra/hurdy-gurdy/workflows/build/badge.svg)](https://github.com/courseorchestra/hurdy-gurdy/actions?query=workflow%3A\"build\")\r\n\r\n![Maven Central Version](https://img.shields.io/maven-central/v/ru.curs/hurdy-gurdy)\r\n\r\n\r\n# Hurdy-Gurdy\r\n\r\nGenerates client and server side Java/Kotlin code based on OpenAPI spec, using [swagger-parser](https://github.com/swagger-api/swagger-parser), [JavaPoet](https://github.com/square/javapoet) and [KotlinPoet](https://github.com/square/kotlinpoet).\r\n\r\n## Usage example (as Maven plugin)\r\n```xml\r\n\u003cplugin\u003e\r\n    \u003cgroupId\u003eru.curs\u003c/groupId\u003e\r\n    \u003cartifactId\u003ehurdy-gurdy\u003c/artifactId\u003e\r\n    \u003cversion\u003e2.7\u003c/version\u003e\r\n    \u003cconfiguration\u003e\r\n        \u003c!--Root package for generated code--\u003e\r\n        \u003crootPackage\u003ecom.example.project\u003c/rootPackage\u003e\r\n        \u003cspec\u003e${basedir}/src/main/openapi/api.yaml\u003c/spec\u003e\r\n        \u003c!--Set to true if you want to have HttpServletResponse response \r\n        parameter in Controller interface: good for server-side code.\r\n        Set to false (default) if you don't need one \r\n        (good for client-side)--\u003e\r\n        \u003cgenerateResponseParameter\u003etrue\u003c/generateResponseParameter\u003e\r\n    \u003c/configuration\u003e\r\n    \u003cexecutions\u003e\r\n        \u003cexecution\u003e\r\n            \u003cgoals\u003e\r\n                \u003cgoal\u003egen-server\u003c/goal\u003e\r\n            \u003c/goals\u003e\r\n        \u003c/execution\u003e\r\n    \u003c/executions\u003e\r\n\u003c/plugin\u003e\r\n```\r\n\r\n## Usage example (in Kotlin code, e.g. Gradle's buildSrc)\r\n\r\n```kotlin\r\nimport ru.curs.hurdygurdy.KotlinCodegen\r\nimport ru.curs.hurdygurdy.GeneratorParams\r\n\r\nval codegen = KotlinCodegen(GeneratorParams.rootPackage(\"com.example.project\"))\r\nval yamlPath = project.layout.projectDirectory.asFile.toPath().resolve(\"src/main/openapi/api.yaml\")\r\nval resultPath = project.layout.buildDirectory.get().asFile.toPath().resolve(\"generated-sources\")\r\nFiles.createDirectories(resultPath)\r\ncodegen.generate(yamlPath, resultPath)\r\n```\r\n\r\n## Configuration parameters\r\n\r\n| Parameter name | Type | Default value | Description |\r\n|--------------------------|------|---------------|-------------|\r\n|`rootPackage`|String | | Sets the root package for all the generated classes. `Controller` and `Api` interfaces will be generated in `controller` subpackage, and all the DTOs will be generated in `dto` subpackage.\r\n|`generateResponseParameter`|boolean|false|Set to true if you need to have `HttpServletResponse` parameter in each generated `Controller` method. You might need this in order to return specific HTTP status codes.\r\n|`generateApiInterface`|boolean|false|Set to true if you need to generate an interface called `Api` besides `Controller`. `Api` methods do not have `HttpServletResponse` parameter.\r\n|`forceSnakeCaseForProperties`|boolean|true|By default, hurdy-gurdy expects all the properties of DTO classes to be defined in _snake_case_ in the specification. It converts these names to _camelCase_ for generated classes and sets Jackson's `SnakeCaseStrategy` so that they will still be _snake_case_ in JSON representation. If you don't want this (e. g. if you want your properties to be defined in _camelCase_ everywhere) you can turn off this function via this parameter. \r\n\r\n## Inheritance hierarchy compatible with openapi-codegen\r\n\r\n```yaml\r\ncomponents:\r\n  schemas:\r\n    #---------------------------------------------------------------------------\r\n    # Abstract class with discriminator 'vehicle_type'\r\n    #---------------------------------------------------------------------------\r\n    'Vehicle':\r\n      type: object\r\n      nullable: false\r\n      properties:\r\n        'vehicle_type':\r\n          type: string\r\n      discriminator:\r\n        propertyName: vehicle_type\r\n        mapping:\r\n          'CAR': '#/components/schemas/Car'\r\n          'TRUCK': '#/components/schemas/Truck'\r\n    #---------------------------------------------------------------------------\r\n    # Concrete classes\r\n    #---------------------------------------------------------------------------\r\n    'Car':\r\n      nullable: false\r\n      allOf:\r\n        - $ref: \"#/components/schemas/Vehicle\"\r\n        - type: object\r\n          properties:\r\n            'car_property':\r\n              type: string\r\n    'Truck':\r\n      nullable: false\r\n      allOf:\r\n        - $ref: \"#/components/schemas/Vehicle\"\r\n        - type: object\r\n          properties:\r\n            'truck_property':\r\n              type: string\r\n```\r\n\r\nThis will produce the following in Java:\r\n```java\r\n//Vehicle.java\r\n@Data\r\n@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)\r\n@JsonTypeInfo(\r\n        use = JsonTypeInfo.Id.NAME,\r\n        include = JsonTypeInfo.As.PROPERTY,\r\n        property = \"vehicle_type\"\r\n)\r\n@JsonSubTypes({\r\n        @JsonSubTypes.Type(value = Car.class, name = \"CAR\"),\r\n        @JsonSubTypes.Type(value = Truck.class, name = \"TRUCK\")})\r\npublic class Vehicle {\r\n}\r\n\r\n//Car.java\r\n@Data\r\n@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)\r\npublic class Car extends Vehicle {\r\n    private String carProperty;\r\n}\r\n```\r\n\r\nThis will produce the following in Kotlin:\r\n\r\n```kotlin\r\n//Vehicle.kt\r\n@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy::class)\r\n@JsonTypeInfo(\r\n  use = JsonTypeInfo.Id.NAME,\r\n  include = JsonTypeInfo.As.PROPERTY,\r\n  property = \"vehicle_type\"\r\n)\r\n@JsonSubTypes(JsonSubTypes.Type(value = Car::class, name = \"CAR\"),\r\nJsonSubTypes.Type(value = Truck::class, name = \"TRUCK\"))\r\npublic sealed class Vehicle()\r\n\r\n//Car.kt\r\n@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy::class)\r\npublic data class Car(\r\n    public val carProperty: String? = null\r\n) : Vehicle()\r\n```\r\n\r\n## Make DTO classes implement interfaces\r\n\r\nYou can use `x-extends` [extended property](https://swagger.io/docs/specification/openapi-extensions/) on schema element in order to make DTO implement given interface or interfaces: \r\n\r\n```yaml\r\ncomponents:\r\n  schemas:\r\n    MenuItemDTO:\r\n      type: object\r\n      nullable: false\r\n      x-extends:\r\n        - java.lang.Serializable\r\n      title: MenuItemDTO\r\n      properties:\r\n        [....]\r\n```\r\n## References to external specifications\r\nYou can use references to external specification files if they are available on the same file system as the original one. However, hurdy-gurdy does not attempt to generate code for referenced specifications: we believe this should be done explicitly for every spec. Hurdy-gurdy just uses `x-package` extension property on the referenced specification in order to define the location of referenced DTOs.\r\n\r\nFor example, given the following spec fragment:\r\n\r\n```yaml\r\n  /api/v1/external:\r\n    get:\r\n      operationId: external\r\n      responses:\r\n        \"200\":\r\n          description: external file\r\n          content:\r\n            text/csv:\r\n              schema:\r\n                $ref: 'externalfile.yaml#/components/schemas/DatabaseConnectionRequest'\r\n```\r\n\r\nThe `externalfile.yaml` file should be located in the same folder and it should contain `x-package` property:\r\n\r\n```yaml\r\nopenapi: 3.0.1\r\ninfo:\r\npaths:\r\nx-package: com.example\r\n```\r\nThen code generator will suggest that `com.example.dto.DatabaseConnectionRequest` class exists on the classpath.\r\n\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcourseorchestra%2Fhurdy-gurdy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcourseorchestra%2Fhurdy-gurdy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcourseorchestra%2Fhurdy-gurdy/lists"}