Cannot get my endpoints list from controller in swagger UI

Viewed 8471

I am new to Spring boot with Swagger UI. I'm just trying to configure my Rest controller endpoints to show on swagger UI screen but it shows No operations for specs defined. Pretty sure, its a configuration issue.

I have tried @EnableAutoConfiguration, still it can't find the controller

SwaggerDemoApplication.java

package com.example.config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

}

SwaggerConfig.java

package com.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.RequestHandlerSelectors;
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;

@EnableSwagger2
@Configuration

public class SwaggerConfig {

 @Bean
 public Docket productApi() {
     return new Docket(DocumentationType.SWAGGER_2)  
              .select()                                  
              .apis(RequestHandlerSelectors.basePackage("com.example.controller"))              
              .paths(regex("/test.*"))                       
              .build();                                           

 } 
}



TestController.java

package com.example.controller;


import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import io.swagger.annotations.Api;

@RestController
@RequestMapping(value = "/test")
@Api(value="onlinestore", description="Operations pertaining to products in Online Store")
public class TestController {

    @RequestMapping(value = "/test-swagger", method= RequestMethod.GET)
    public String home() {
        return "Spring is here!";
    }

}

Expected: Rest endpoint Actual: No operations defined in spec

4 Answers

I had exactly the same problem like you and it was caused with the wrong placement of my @SpringBootApplication class, just like you have it.

(In the code snippets, I am intentionally omitting less relevant annotations, they still must be there as you have them in your post.

I also quote the words like "under", "root package" etc., as technically Java does not recognize anything like a "sub-package". All the packages in Java are at the same "level", even if the dots and the resemblance of the web domains "mislead" us to think about them hierarchically. However Spring extensively works with "sub-packages" and "root-packages".)

package com.example.config;
@SpringBootApplication
public class SwaggerDemoApplication {
    ...
}

package com.example.config;
@EnableSwagger2
public class SwaggerConfig {
      ...
      .apis(RequestHandlerSelectors.basePackage("com.example.controller"))              
      ...
}

@RestController
package com.example.controller; // notice that this is not "under" com.example.config where SwaggerDemoApplication resides
public class TestController {
    ....
}

I observed that if the @SpringBootApplication class is not in the "root package" of the @RestController class, it breaks the automagical behaviour and the package name set in the call of apis(...) is ignored and the package is not scanned. To be honest, I am not very much sure how the apis() is supposed to work and whether it is a bug or a feature.

To fix it without adding @ComponentScan, your package organisation should be something like this:

package com.example.myapplication; // the main class is placed in the "root" package
@SpringBootApplication
public class SwaggerDemoApplication {
    ...
}

package com.example.myapplication.config;
@EnableSwagger2
public class SwaggerConfig {
      ...
      .apis(RequestHandlerSelectors.basePackage("com.example.myapplication"))
      ...
}

package com.example.myapplication.controller;
@RestController
public class TestController {
    ...
}

You may also further filter the API scanning by specifying

.apis(
    withClassAnnotation(RestController.class)
    .and(basePackage("com.example.myapplication.controller))
)

You can try it in this way.
Path you specified can be the problematic.

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket docket() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("<your-package>"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("API Documentation")
                .description("This API documentation is related <something>")
                .version("1.0.0")
                .build();
    }
}

SwaggerConfig.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class SwaggerConfig implements WebMvcConfigurer{

    @Override 
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }   

   @Bean
   public Docket apiDocket() {

       Docket docket =  new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.example"))
                .paths(PathSelectors.any())
                .build();

       return docket;

    } 
}

SwaggerDemoApplication.java

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

pom.xml

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

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-core</artifactId>
            <version>2.9.2</version>
        </dependency>

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

In Case you are using Spring Security you have to add below Configurations

 @Override
    public void configure(WebSecurity web) throws Exception {
        web
          .ignoring()  
            .antMatchers("/v2/api-docs", "/configuration/**", "/swagger*/**", "/webjars/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception{

         http
         .csrf().disable()
         .authorizeRequests()
         .antMatchers("/v2/api-docs", "/configuration/**", "/swagger*/**", "/webjars/**")
         .permitAll()
         .anyRequest().authenticated();
    }

The problem is not your Swagger Configuration but your Controller is not scanned as Spring resource class.

Because your application startup class (Main class) has no @ComponentScan annotation.

So, your class should be like this:

@EnableSwagger2
@SpringBootApplication
@ComponentScan("com.example")
public class SwaggerDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SwaggerDemoApplication.class, args);
    }
}

Now you can access your API documentation from here http://localhost:8098/swagger-ui.html#

Related