Reputation: 3560
I have a Spring Boot project with springfox-swagger-2 as dependency.
Versions used:
This is the configuration:
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket api() {
Docket api = new Docket(DocumentationType.SWAGGER_2);
api
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
api.apiInfo(apiInfo())
.globalOperationParameters(Lists.newArrayList(new ParameterBuilder()
.name("Example api info")
.description("description")
.modelRef(new ModelRef("string"))
.parameterType("parameter type example").build()))
;
return api;
}
@SuppressWarnings("rawtypes")
private ApiInfo apiInfo() {
Contact contact = new Contact("name", "url", "email");
Collection<VendorExtension> vendorExtensions = new ArrayList<>();
return new ApiInfo("title", "description", "version", "termsOfServiceUrl", contact, "license", "licenseUrl", vendorExtensions);
}
}
The application starts correctly, but the url /v2/api-docs
gets an HTTP 404 Not Found
Even the /swagger-ui.html is not available adding the dependency for springfox-swagger-ui
The bootstrap log doesn't report any error.
I already tried to find the answer on other similar questions but any of them is working!
Any help would be appreciated.
Upvotes: 0
Views: 6308
Reputation: 1383
In case the person stuck is a noob like me, make sure you have run the Maven Install command after adding the dependencies in the pom.xml file.
Upvotes: 0
Reputation: 330
I also stumbled upon an HTTP 404 Not Found for /v2/api-docs
(but during a unit test) as part of migrating Spring Boot from version 2.0.4.RELEASE to version 2.1.6.RELEASE. The unit test passed before the "upgrade".
The unit test class had the following annotations:
@Category(UnitIntegrationTest.class)
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(classes = {SecurityConfiguration.class})
@ActiveProfiles("test")
and the test configuration was defined as an inner class:
@Configuration
@EnableWebMvc
@EnableSwagger2
@Import(value = BeanValidatorPluginsConfiguration.class)
public static class TestSwaggerConfiguration {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("the.package.we.want"))
.paths(PathSelectors.any())
.build();
}
}
The fix was to specify the TestSwaggerConfiguration
in the @ContextConfiguration
, e.g.:
@Category(UnitIntegrationTest.class)
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(classes = {SecurityConfiguration.class, GenerateDocumentationTest.TestSwaggerConfiguration.class})
@ActiveProfiles("test")
As a side note, before hitting the HTTP 404 I also had to specify
spring.main.allow-bean-definition-overriding=true
in the application-test.properties
as per the Spring Boot 2.1 Release Notes.
Upvotes: 0
Reputation: 3560
Finally I have found the way to make it work.
The springfox-swagger-2 implementation has a @Controller
within the class springfox.documentation.swagger2.web.Swagger2Controller
.
This class implements the mapping for the url "/v2/api-docs"
with this method:
@RequestMapping(
value = DEFAULT_URL,
method = RequestMethod.GET,
produces = { APPLICATION_JSON_VALUE, HAL_MEDIA_TYPE })
@PropertySourcedMapping(
value = "${springfox.documentation.swagger.v2.path}",
propertyKey = "springfox.documentation.swagger.v2.path")
@ResponseBody
public ResponseEntity<Json> getDocumentation(
@RequestParam(value = "group", required = false) String swaggerGroup,
HttpServletRequest servletRequest) {
String groupName = Optional.fromNullable(swaggerGroup).or(Docket.DEFAULT_GROUP_NAME);
Documentation documentation = documentationCache.documentationByGroup(groupName);
if (documentation == null) {
return new ResponseEntity<Json>(HttpStatus.NOT_FOUND);
}
Swagger swagger = mapper.mapDocumentation(documentation);
UriComponents uriComponents = componentsFrom(servletRequest, swagger.getBasePath());
swagger.basePath(Strings.isNullOrEmpty(uriComponents.getPath()) ? "/" : uriComponents.getPath());
if (isNullOrEmpty(swagger.getHost())) {
swagger.host(hostName(uriComponents));
}
return new ResponseEntity<Json>(jsonSerializer.toJson(swagger), HttpStatus.OK);
}
As you can see, the RequestMapping expects a parameter named "group"
.
So, if you call the "/v2/api-docs"
url without the "group"
parameter, the documentation obtained is null because there are no documentations in the cache for the key ""
(empty String).
I solved adding a custom Filter implemented in this way:
@Component
public class SwaggerFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
String group = req.getParameter("group");
if (req.getServletPath().equals("/v2/api-docs") && group==null) {
res.sendRedirect("api-docs?group=default");
} else {
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
}
}
The mechanism is simple: without the "group"
parameter, there is a redirect with the "default"
group parameter.
Upvotes: 0
Reputation: 13727
SwaggerConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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 {
@Bean
public Docket apiDocket() {
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.."))
.paths(PathSelectors.any())
.build();
return docket;
}
}
SecurityConfig.java
public class SecurityConfig extends WebSecurityConfigurerAdapter implements WebMvcConfigurer{
@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();
}
@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/");
}
}
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>
Upvotes: 1
Reputation: 1424
try to add this to yourapplication.properties
spring.resources.add-mappings=true
Upvotes: 0