8

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?

Sergei Podlipaev
  • 1,331
  • 1
  • 14
  • 34
  • 1
    It seems like springfox doesn't support OAS 3.0 - https://github.com/springfox/springfox/issues/2022. Can you suggest any other libs that generate swagger from spec? – Sergei Podlipaev Apr 17 '19 at 13:43
  • Possible duplicate of [Where the Swagger pretty HTML code?](https://stackoverflow.com/questions/44803881/where-the-swagger-pretty-html-code), [How to embed Swagger UI to a webpage?](https://stackoverflow.com/q/46237255/113116) – Helen Apr 17 '19 at 14:50
  • Swagger UI is available standalone at https://github.com/swagger-api/swagger-ui/ and you can host it yourself separately from the app code. You don't generate it from an OpenAPI spec, instead you take Swagger UI and connect it to your spec. See the ^^ linked questions. – Helen Apr 17 '19 at 14:52

1 Answers1

11

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.

Sergei Podlipaev
  • 1,331
  • 1
  • 14
  • 34
  • Thank you Sergei, this helped me A LOT to solve my issue as well. Why did sou choose the "spec" variable which resulted in 3 replacements? Replacing the petstore.json url with the local openapi.json worked just fine for me: `https:\/\/petstore\.swagger\.io\/v2\/swagger\.jsonopenapi.json` I used the output for a gitlab pages doc. In this case I had to delete the index.html.gz so actually my modified index.html was picked up. – Ralf Sep 20 '19 at 14:23
  • @mineralf thx, I'll check it. Also I plan to check how to build swagger UI from multiple specification files. Will post it here after find a solution – Sergei Podlipaev Sep 25 '19 at 16:21