Search code examples
javaswaggeropenapispringfox

Java - how to generate Swagger UI directly from openapi 3.0 specification


I have openapi 3.0 specification in yaml format and my application that generates code from it. Everything works fine except generation of swagger ui. I use spring-fox for its generation, but it seems like it generates swagger ui 2.0 version from controllers, that are generated from openapi specification.

How can I generate swagger ui directly from my 3.0 spec and not from controllers, that are generated from 3.0 openapi spec?


Solution

  • Well I have solved the problem (the solution is pretty cumbersome though).

    First of all I added swagger ui webjar -

            <plugin>
                <!-- Download Swagger UI webjar. -->
                <artifactId>maven-dependency-plugin</artifactId>
                <version>${maven-dependency-plugin.version}</version>
                <executions>
                    <execution>
                        <phase>prepare-package</phase>
                        <goals>
                            <goal>unpack</goal>
                        </goals>
                        <configuration>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>org.webjars</groupId>
                                    <artifactId>swagger-ui</artifactId>
                                    <version>${swagger-ui.version}</version>
                                </artifactItem>
                            </artifactItems>
                            <outputDirectory>${project.build.directory}/classes</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
    

    Then I transform my yaml specification to json format and copy it to swagger-ui webjar directory:

                <plugin>
                    <groupId>org.openapitools</groupId>
                    <artifactId>openapi-generator-maven-plugin</artifactId>
                    <version>4.0.0-beta3</version>
                    <executions>                    
                        <execution>
                            <id>generate-spec</id>
                            <goals>
                                <goal>generate</goal>
                            </goals>
                            <configuration>
                                <inputSpec>${openapi-spec-file-location}</inputSpec>
                                <validateSpec>true</validateSpec>
                                <generatorName>openapi</generatorName>
                                <output>${project.build.directory}/classes/META-INF/resources/webjars/swagger-ui/${swagger-ui.version}</output>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
    

    Next we need to set specification path in swagger-ui. According to swagger-ui API we can pass spec JSON variable instead of url. So to initialize this spec variable and to edit swagger ui rendering I use replacer plugin in maven:

                <plugin>
                    <!-- Replace the OpenAPI specification example URL with the local one. -->
                    <groupId>com.google.code.maven-replacer-plugin</groupId>
                    <artifactId>replacer</artifactId>
                    <version>1.5.3</version>
                    <executions>
                        <execution>
                            <phase>prepare-package</phase>
                            <goals>
                                <goal>replace</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <includes>
                            <!-- Static index html with swagger UI rendering and OAS in JSON format. -->
                            <include>${project.build.directory}/classes/META-INF/resources/webjars/swagger-ui/${swagger-ui.version}/index.html</include>
                            <include>${project.build.directory}/classes/META-INF/resources/webjars/swagger-ui/${swagger-ui.version}/openapi.json</include>
                        </includes>
                        <regexFlags>
                            <regexFlag>CASE_INSENSITIVE</regexFlag>
                            <regexFlag>MULTILINE</regexFlag>
                        </regexFlags>
                        <replacements>
                            <!-- This replacement imports spec json variable into static html page. -->
                            <replacement>
                                <token>&lt;script&gt;</token>
                                <value>&lt;script src="./openapi.json"&gt; &lt;/script&gt;&lt;script&gt;</value>
                            </replacement>
                            <!-- This part replaces url input variable with spec variable. -->
                            <replacement>
                                <token>url:\s"https:\/\/petstore\.swagger\.io\/v2\/swagger\.json"</token>
                                <value>spec: spec</value>
                            </replacement>
                            <replacement>
                            <!-- This replacement initializes spec variable, that will be passed to swagger ui index.html. -->
                                <token>^\{</token>
                                <value>spec = {</value>
                            </replacement>
                        </replacements>
                    </configuration>
                </plugin>
    

    So at this step after build we got static resource with swagger ui. Last thing to do is to serve it with Spring.

    @Configuration
    @EnableWebMvc
    public class SwaggerConfiguration implements WebMvcConfigurer {
    
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/**")
                    .addResourceLocations("classpath:/META-INF/resources/webjars/swagger-ui/3.22.0/");
        }
    
        //this method was introduced just for convenient swagger ui access. Without it swagger ui can be accessed with /index.html GET call   
        @Override
        public void addViewControllers(ViewControllerRegistry registry) {
            registry.addViewController("/swagger-ui.html").setViewName("forward:/index.html");
        }
    }
    

    So this is it. It would be great if you comment this answer and point on how to simplify this procedure.