spring-bootswaggeropenapiopenapi-generatoropenapi-generator-maven-plugin

Springboot openapi generating duplicate apis in swagger document


Java: 21

Springboot: 3.2.1

OpenApi dependency:

<dependency>
      <groupId>org.springdoc</groupId>
      <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
      <version>2.1.0</version>
    </dependency>

Open api yaml file

openapi: 3.0.3
info:
  title: Example apis
  description: |-
    A simple collection of example APIs
  version: 1.0-SNAPSHOT
servers:
  - url: http://127.0.1:8091/api/v1
    description: Local server (uses test data)
  - url: https://example-dev.com/api/v1
    description: UAT server (uses test data)
  - url: https://example.com/api/v1
    description: Production server (uses live data)
tags:
  - name: example
    description: example apis
paths:
  /examples:
    get:
      summary: Get examples
      description: Get examples
      operationId: getExample
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Example'
        404:
          description: Leaderboard not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExampleNotFoundError'
  
components:
  schemas:
    Example:
      type: object
      properties:
        creatorId:
          type: string
        hipiCoins:
          type: number
    ExampleNotFoundError:
      type: object
      properties:
        creatorId:
          type: string
        hipiCoins:
          type: number
    

In swagger, there are two apis

One is GET /api/v1/examples and another is GET /examples

Expected only GET /api/v1/examples

There are few similar questions in stacker flow, I tried all of them one by one in last 8 hours, none is solving the issue.

Controller code:

@Generated(
    value = "org.openapitools.codegen.languages.SpringCodegen",
    date = "2024-01-15T23:26:32.308871+05:30[Asia/Kolkata]")
@Controller
public class ExampleController implements ExampleApi {

  private final ExampleApiDelegate delegate;

  public ExampleController(
      @org.springframework.beans.factory.annotation.Autowired(required = false)
          ExampleApiDelegate delegate) {
    this.delegate = Optional.ofNullable(delegate).orElse(new ExampleApiDelegate() {});
  }

  @Override
  public ExampleApiDelegate getDelegate() {
    return delegate;
  }
}

Application.properties

spring.application.name=example-service
server.port=8091
springdoc.enable-native-support=true
springdoc.swagger-ui.path=/swagger-ui
logging.level.root=INFO

Solution

  • It gets resolve with below changes

    In pom.xml

    <plugin>
            <groupId>org.openapitools</groupId>
            <artifactId>openapi-generator-maven-plugin</artifactId>
            <version>6.2.1</version>
            <executions>
              <execution>
                <goals>
                  <goal>generate</goal>
                </goals>
                <configuration>
                  <skipValidateSpec>true</skipValidateSpec>
                  <inputSpec>./src/main/resources/example.yaml</inputSpec>
                  <generatorName>spring</generatorName>
                  <apiPackage>com.example.openapi.api</apiPackage>
                  <modelPackage>com.example.openapi.model</modelPackage>
                  <supportingFilesToGenerate>
                    ApiUtil.java
                  </supportingFilesToGenerate>
                  <configOptions>
                    <delegatePattern>true</delegatePattern>
                    <useSpringBoot3>true</useSpringBoot3>
                  </configOptions>
                </configuration>
              </execution>
            </executions>
          </plugin>
    

    Now in target folder it generates ExampleApiDelegate and ExampleApi both, but we need to extend ExampleApiDelegate

    @Generated(
        value = "org.openapitools.codegen.languages.SpringCodegen",
        date = "2024-01-15T23:26:32.308871+05:30[Asia/Kolkata]")
    @Controller
    public class ExampleController implements ExampleApiDelegate {
    
      private final ExampleApiDelegate delegate;
    
      public ExampleController(
          @org.springframework.beans.factory.annotation.Autowired(required = false)
              ExampleApiDelegate delegate) {
        this.delegate = Optional.ofNullable(delegate).orElse(new ExampleApiDelegate() {});
      }
    
      @Override
      public ExampleApiDelegate getDelegate() {
        return delegate;
      }
    }