9

I am trying to configure Swagger UI with my Spring boot application. Although the v2/api-docs seems to be loading properly, the http://localhost:8080/swagger-ui.html does not load my annotated REST API.

Here is what I have:

pom.xml:

...
<!--Swagger UI-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.6.1</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.4.0</version>
        </dependency>
...

SwaggerConfig.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import static springfox.documentation.builders.PathSelectors.regex;

@Configuration
@EnableSwagger2
public class SwaggerConfig
{
    @Bean
    public Docket api()
    {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(regex("/.*"))
                .build().apiInfo(apiInfo());
    }

    private ApiInfo apiInfo()
    {
        ApiInfo apiInfo = new ApiInfo(
                "My Project's REST API",
                "This is a description of your API.",
                "version-1",
                "API TOS",
                "me@wherever.com",
                "API License",
                "API License URL"
        );
        return apiInfo;
    }
}

http://localhost:8080/v2/api-docs:

{"swagger":"2.0","info":{"description":"This is a description of your API.","version":"version-1","title":"My Project's REST API","termsOfService":"API TOS","contact":{"name":"me@wherever.com"},"license":{"name":"API License","url":"API License URL"}},"host":"localhost:8080","basePath":"/","tags":[{"name":"test-controller","description":"Test Controller"},{"name":"custom-field-controller","description":"Custom Field Controller"},{"name":"user-controller","description":"User Controller"},{"name":"users-controller","description":"Users Controller"},{"name":"crudapi-controller","description":"CRUDAPI Controller"},{"name":"basic-error-controller","description":"Basic Error Controller"}],"paths":{"/":{"get":{"tags":["crudapi-controller"],"summary":"greeting","operationId":"greetingUsingGET","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"string"}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}}},"/api/javainuse":{"get":{"tags":["test-controller"],"summary":"firstPage","operationId":"firstPageUsingGET","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"string"}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}}},"/error":{"get":{"tags":["basic-error-controller"],"summary":"errorHtml","operationId":"errorHtmlUsingGET","consumes":["application/json"],"produces":["text/html"],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/ModelAndView"}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}},"head":{"tags":["basic-error-controller"],"summary":"errorHtml","operationId":"errorHtmlUsingHEAD","consumes":["application/json"],"produces":["text/html"],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/ModelAndView"}},"401":{"description":"Unauthorized"},"204":{"description":"No Content"},"403":{"description":"Forbidden"}}},"post":{"tags":["basic-error-controller"],"summary":"errorHtml","operationId":"errorHtmlUsingPOST","consumes":["application/json"],"produces":["text/html"],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/ModelAndView"}},"201":{"description":"Created"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}},"put":{"tags":["basic-error-controller"],"summary":"errorHtml","operationId":"errorHtmlUsingPUT","consumes":["application/json"],"produces":["text/html"],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/ModelAndView"}},"201":{"description":"Created"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}},"delete":{"tags":["basic-error-controller"],"summary":"errorHtml","operationId":"errorHtmlUsingDELETE","consumes":["application/json"],"produces":["text/html"],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/ModelAndView"}},"401":{"description":"Unauthorized"},"204":{"description":"No Content"},"403":{"description":"Forbidden"}}},"options":{"tags":["basic-error-controller"],"summary":"errorHtml","operationId":"errorHtmlUsingOPTIONS","consumes":["application/json"],"produces":["text/html"],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/ModelAndView"}},"401":{"description":"Unauthorized"},"204":{"description":"No Content"},"403":{"description":"Forbidden"}}},"patch":{"tags":["basic-error-controller"],"summary":"errorHtml","operationId":"errorHtmlUsingPATCH","consumes":["application/json"],"produces":["text/html"],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/ModelAndView"}},"401":{"description":"Unauthorized"},"204":{"description":"No Content"},"403":{"description":"Forbidden"}}}},"/fields":{"get":{"tags":["custom-field-controller"],"summary":"greeting","operationId":"greetingUsingGET_1","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"string"}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}}},"/fields/{id}":{"get":{"tags":["custom-field-controller"],"summary":"fieldAPIController","operationId":"fieldAPIControllerUsingGET","consumes":["application/json"],"produces":["*/*"],"parameters":[{"name":"id","in":"path","description":"id","required":true,"type":"integer","format":"int32"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/CustomField"}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}}},"/users":{"get":{"tags":["user-controller"],"summary":"greeting","operationId":"greetingUsingGET_2","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"string"}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}}},"/users/":{"get":{"tags":["users-controller"],"summary":"listUsers","operationId":"listUsersUsingGET","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/UserJPA"}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}},"head":{"tags":["users-controller"],"summary":"listUsers","operationId":"listUsersUsingHEAD","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/UserJPA"}}},"401":{"description":"Unauthorized"},"204":{"description":"No Content"},"403":{"description":"Forbidden"}}},"post":{"tags":["users-controller"],"summary":"listUsers","operationId":"listUsersUsingPOST","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/UserJPA"}}},"201":{"description":"Created"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}},"put":{"tags":["users-controller"],"summary":"listUsers","operationId":"listUsersUsingPUT","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/UserJPA"}}},"201":{"description":"Created"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}},"delete":{"tags":["users-controller"],"summary":"listUsers","operationId":"listUsersUsingDELETE","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/UserJPA"}}},"401":{"description":"Unauthorized"},"204":{"description":"No Content"},"403":{"description":"Forbidden"}}},"options":{"tags":["users-controller"],"summary":"listUsers","operationId":"listUsersUsingOPTIONS","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/UserJPA"}}},"401":{"description":"Unauthorized"},"204":{"description":"No Content"},"403":{"description":"Forbidden"}}},"patch":{"tags":["users-controller"],"summary":"listUsers","operationId":"listUsersUsingPATCH","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/UserJPA"}}},"401":{"description":"Unauthorized"},"204":{"description":"No Content"},"403":{"description":"Forbidden"}}}},"/users/{id}":{"get":{"tags":["user-controller"],"summary":"userAPIController","operationId":"userAPIControllerUsingGET","consumes":["application/json"],"produces":["*/*"],"parameters":[{"name":"id","in":"path","description":"id","required":true,"type":"integer","format":"int32"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/Collection«UserJPA»"}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}}}},"definitions":{"UserJPA":{"type":"object"},"Collection«UserJPA»":{"type":"object"},"ModelAndView":{"type":"object","properties":{"empty":{"type":"boolean"},"model":{"type":"object"},"modelMap":{"type":"object","additionalProperties":{"type":"object"}},"reference":{"type":"boolean"},"status":{"type":"string","enum":["100","101","102","103","200","201","202","203","204","205","206","207","208","226","300","301","302","303","304","305","307","308","400","401","402","403","404","405","406","407","408","409","410","411","412","413","414","415","416","417","418","419","420","421","422","423","424","426","428","429","431","451","500","501","502","503","504","505","506","507","508","509","510","511"]},"view":{"$ref":"#/definitions/View"},"viewName":{"type":"string"}}},"CustomField":{"type":"object","properties":{"name":{"type":"string"}}},"View":{"type":"object","properties":{"contentType":{"type":"string"}}}}}

The swagger-ui.html (http://localhost:8080/swagger-ui.html) does not show the expected REST calls: enter image description here

The error in swagger-ui.html from the code inspection: Failed to load resource: the server responded with a status of 404 ().

I have googled around (tried web-config mvc too) but the error persists. Maybe I am missing a resource reference in the .iml file?

Menelaos Kotsollaris
  • 5,776
  • 9
  • 54
  • 68
  • 1
    That's the wrong URL `configuration/ui`. It leads me to believe it will go away if reset your browser cache. It should be URL `swagger-resources/configuration/ui`. – Dilip Krishnan Apr 26 '17 at 22:01

5 Answers5

8

I had this issue today and fixed it by matching up the versions of my springfox-swagger2 and springfox-swagger-ui dependencies:

    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>2.6.1</version>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>2.6.1</version>
    </dependency>

There's very little other code to just get it up and running. One simple config class:

@Configuration
@EnableSwagger2
class SwaggerConfiguration {

    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.foo.samples.swaggersample"))
                .paths(PathSelectors.any())
                .build();
    }

}

And my application.properties

# location of the swagger json
springfox.documentation.swagger.v2.path=/swagger.json

(This is in Spring Boot).

Paul J
  • 799
  • 1
  • 6
  • 16
  • Didn't fix the problem. Maybe you changed something else too? Could you please provide your swagger-ui code? – Menelaos Kotsollaris May 01 '17 at 00:46
  • Thanks, this helped a lot. Additionally I added `@Import` the SwaggerConfig class to the spring config, and whitelisted `/v2/api-docs`, `/configuration/ui`, `/swagger-resources`, `/configuration/security`, `/swagger-ui.html` and `/swagger.json` through WebSecurity configuration. – Václav Blažej Aug 11 '17 at 15:59
2

Statement : Generate Swagger UI for the listing of all the REST APIs through Spring Boot Application.

Follow the below steps to generate the Swagger UI through Spring Boot application:

1. Add following dependency in pom.xml –

    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>2.6.1</version>
    </dependency>

    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>2.6.1</version>
    </dependency>

2. Add the following piece of code in your main application class having the @EnableSwagger2 annotation.

    @EnableSwagger2
    @SpringBootApplication
    public class MyApp {
    public static void main(String[] args) {
        SpringApplication.run(MyApp.class, args);
    }

    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2).select()  
           .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
           .paths(PathSelectors.any()).build().pathMapping("/")
           .apiInfo(apiInfo()).useDefaultResponseMessages(false);
    }

    @Bean
    public ApiInfo apiInfo() {
        final ApiInfoBuilder builder = new ApiInfoBuilder();
        builder.title("My Application API through Swagger UI").version("1.0").license("(C) Copyright Test")
        .description("List of all the APIs of My Application App through Swagger UI");
        return builder.build();
        }
    }

3. Add the below RootController class in your code to redirect to the Swagger UI page. In this way, you don’t need to put the dist folder of Swagger-UI in your resources directory.

    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    @Controller
    @RequestMapping("/")
    public class RootController {
        @RequestMapping(method = RequestMethod.GET)
        public String swaggerUi() {
            return "redirect:/swagger-ui.html";
        }
    }

4. Being the final steps, add the @Api and @ApiOperation notation in all your RESTControllers like below –

    import static org.springframework.web.bind.annotation.RequestMethod.GET;
    import org.springframework.http.HttpStatus;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.ResponseStatus;
    import org.springframework.web.bind.annotation.RestController;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;

    @RestController
    @RequestMapping("/hello")
    @Api(value = "hello", description = "Sample hello world application")
    public class TestController {

        @ApiOperation(value = "Just to test the sample test api of My App Service")
        @RequestMapping(method = RequestMethod.GET, value = "/test")
        // @Produces(MediaType.APPLICATION_JSON)
        public String test() {
            return "Hello to check Swagger UI";
        }

        @ResponseStatus(HttpStatus.OK)
        @RequestMapping(value = "/test1", method = GET)
        @ApiOperation(value = "My App Service get test1 API", position = 1)
        public String test1() {
            System.out.println("Testing");
            if (true) {
                return "Tanuj";
            }
            return "Gupta";
        }
    }

Now your are done. Now to run your Spring Boot Application, go to browser and type localhost:8080. You will see Swagger UI having all the details of your REST APIs.

Happy Coding.
The source code of the above implementation is also on my blog if you feel like checking it out.

Mateus
  • 4,863
  • 4
  • 24
  • 32
user2014334
  • 122
  • 1
  • 9
1

Swagger is Available with V2 and V3 version

More minimal config

Check this Answer - https://stackoverflow.com/a/64333853/410439

enter image description here

Ravi Parekh
  • 5,253
  • 9
  • 46
  • 58
0

Add a config class like this

@Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {

  @Override
  public void addResourceHandlers(final ResourceHandlerRegistry registry) {
    // Make Swagger meta-data available via <baseURL>/v2/api-docs/
    registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    // Make Swagger UI available via <baseURL>/swagger-ui.html
    registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/");
  }
}
pvpkiran
  • 25,582
  • 8
  • 87
  • 134
0

Nowadays, just set

springdoc.swagger-ui.disable-swagger-default-url=true
Adam Ostrožlík
  • 1,256
  • 1
  • 10
  • 16