springfox: Swagger ui stuck on unable to infer base url

Hello,

I am trying to run swagger-ui via springfox. My service is behind an edge service, and from swagger I am constantly getting the error : screen shot 2017-08-23 at 16 01 41

My docket config is as follows

return new Docket(DocumentationType.SWAGGER_2)
                .host("http://localhost:8999")
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.any())
                .build();

I have tried different possibilities of host configuration, including not providing it at all.

I can access the docs json from http://localhost:8999/v2/api-docs just fine. When I try to set the base url through this message, no matter what I enter, the dialog flickers and just stands there. I check the network and the browser makes a request to /configuration, which seems to return 200.

I have no idea what to do at this point. Does anyone have any idea ?

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 60 (10 by maintainers)

Most upvoted comments

I had the same problem using Spring Boot 2.0.0.M4 + Spring Security. This solved my issue:

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
class SecurityConfig extends WebSecurityConfigurerAdapter {

    private static final String[] AUTH_WHITELIST = {

            // -- swagger ui
            "/swagger-resources/**",
            "/swagger-ui.html",
            "/v2/api-docs",
            "/webjars/**"
    };
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers(AUTH_WHITELIST).permitAll()
                .antMatchers("/**/*").denyAll();
    }
}

I don’t know, if the whitelist is complete or correct at all. But it solves the issue described above.

Do you have the

@EnableSwagger2

annotation on your SpringApplication? If missing, causes popping up the above message box!

i faced the same problem make sure your swagger configuration is under your spring boot application which can be scanned. and then it solved.

Try to clear the browser cache.

@logicaleak Ok, thank you - it seems to be the same symptom for a different reason in my case. However, maybe it is useful for someone (like me) googling that error message.

Here is what I get if I remove “/swagger-resource/**” from the AUTH_WHITELIST described above:

screen shot 2017-10-09 at 15 32 50

The message is promoted in a catch block which does not determine or throw actual http error code which is confusing for many. In short any problem in invoking and the url or getting the response output will throw this error which could be due to URL context/base path issue, permission issue, spring web container not returning json values etc. ( In my case web container was returning xml and also initially i did not have protected urls )

Best solution from framework point of view will be to catch different exceptions and give appropriate message to users.

I resolved it by adding the config package name “com.companyname.api.config” where I have kept my SwaggerConfiguration file in component scan @ComponentScan(value = { “com.companyname.api.config”})

You mean swagger-ui? Yes it does, but you need to configure it correctly for it to work. The simplest option is to permit anonymous access to

  • /swagger-ui.html
  • /swagger-resources/**
  • /v2/api-docs
  • /webjars/** as shown here.

If thats not an option you’d need to protect some of those resources via basic authentication, typically an authentication mechanism (may be different from the one protecting the APIs themselves).

In spring boot application after making these changes in objectMapper swagger stops working changes done are below: @Bean public Jackson2ObjectMapperBuilder jacksonBuilder() { Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); builder.featuresToEnable(DeserializationFeature.UNWRAP_ROOT_VALUE); builder.featuresToEnable(SerializationFeature.WRAP_ROOT_VALUE); return builder; }

If I remove these above changes swagger starts working.

The solution suggested by @danieldietrich worked for me 😃

Same problem here. Swagger 2.9.2, adding my SpringFoxConfigclass to getRootConfigClasses solve the problem.

public class ApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer  {
@Override
protected Class<?>[] getRootConfigClasses() {
	return new Class[] { ApplicationConfiguration.class, SpringFoxConfig.class };
}

@Override
protected Class<?>[] getServletConfigClasses() {
	return null;
}

@Override
protected String[] getServletMappings() {
	return new String[] { "/" };
}
}

In my case I made the mistake of placing Swagger config class outside of main application package, moved it to main package of my application and it worked:

Bad

src/main/java
│    
│   
└───myproyec
│   │   MyPriyectApplication.class
│   │
│   └───models
│   │
│   └───controllers
│   
└───config
    │   SwaggerConfig.class ❌ 

Ok

src/main/java
│    
│   
└───myproyec
│   │   MyPriyectApplication.class
│   │
│   └───config
│   │   SwaggerConfig.class ✔️  
│   │
│   └───models
│   │
│   └───controllers

image myconfig:

import com.fasterxml.classmate.TypeResolver;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.context.request.async.DeferredResult;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger.web.*;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import springfox.documentation.builders.ResponseBuilder;
import springfox.documentation.schema.ScalarType;
import springfox.documentation.schema.WildcardType;

import java.time.LocalDate;
import java.util.List;

import static java.util.Collections.singletonList;
import static springfox.documentation.schema.AlternateTypeRules.newRule;

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    public SwaggerConfig(TypeResolver typeResolver) {
        this.typeResolver = typeResolver;
    }

    @Bean
    public Docket createRestApi() {

        return new Docket(DocumentationType.OAS_30)

                .apiInfo(apiInfo())

                .select()

                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))

                .paths(PathSelectors.any())

                .build()
                .pathMapping("/")
                .directModelSubstitute(LocalDate.class, String.class)
                .genericModelSubstitutes(ResponseEntity.class)
                .alternateTypeRules(
                        newRule(typeResolver.resolve(DeferredResult.class,
                                typeResolver.resolve(ResponseEntity.class, WildcardType.class)),
                                typeResolver.resolve(WildcardType.class)))
                .useDefaultResponseMessages(false)
                .globalResponses(HttpMethod.GET,
                        singletonList(new ResponseBuilder()
                                .code("500")
                                .description("500 message")
                                .representation(MediaType.TEXT_XML)
                                .apply(r ->
                                        r.model(m ->
                                                m.referenceModel(ref ->
                                                        ref.key(k ->
                                                                k.qualifiedModelName(q ->
                                                                        q.namespace("some:namespace")
                                                                                .name("ERROR"))))))
                                .build()))
                .enableUrlTemplating(true)
                .globalRequestParameters(
                        singletonList(new springfox.documentation.builders.RequestParameterBuilder()
                                .name("someGlobalParameter")
                                .description("Description of someGlobalParameter")
                                .in(ParameterType.QUERY)
                                .required(true)
                                .query(q -> q.model(m -> m.scalarModel(ScalarType.STRING)))
                                .build()));

    }
    private ApiInfo apiInfo() {

        return new ApiInfoBuilder()

                .title("Swagger3接口文档")

                .description("更多请咨询服务开发者XXX")

                .contact(new Contact("作者", "作者地址", "作者邮箱"))

                .version("1.0")

                .build();

    }

    @Autowired
    private TypeResolver typeResolver;
    List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope
                = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        return singletonList(
                new SecurityReference("mykey", authorizationScopes));
    }
    private SecurityContext securityContext() {
        return SecurityContext.builder()
                .securityReferences(defaultAuth())
                .forPaths(PathSelectors.regex("/anyPath.*"))
                .build();
    }
    @Bean
    UiConfiguration uiConfig() {
        return UiConfigurationBuilder.builder()
                .deepLinking(true)
                .displayOperationId(false)
                .defaultModelsExpandDepth(1)
                .defaultModelExpandDepth(1)
                .defaultModelRendering(ModelRendering.EXAMPLE)
                .displayRequestDuration(false)
                .docExpansion(DocExpansion.NONE)
                .filter(false)
                .maxDisplayedTags(null)
                .operationsSorter(OperationsSorter.ALPHA)
                .showExtensions(false)
                .showCommonExtensions(false)
                .tagsSorter(TagsSorter.ALPHA)
                .supportedSubmitMethods(UiConfiguration.Constants.DEFAULT_SUBMIT_METHODS)
                .validatorUrl(null)
                .build();
    }

}

thanks @ktprezes … with your solution, i resolved my problem…

Version 2.9.2 is not working on AWS ALB, it has same issue as mentioned by oeresundsgruppen commented on 5 Nov 2018. /api/null/swagger-resources/configuration/ui is being accessed. not sure why null is being added.

At local it works OK though with localhost.

This is the config I have …/swagger-resources/configuration/ui" is being redirected to /api/null/swagger-resources/configuration/ui.

/** * {@inheritDoc} */ @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addRedirectViewController(“/api/customer-api/api-docs”, “/api/api-docs”).setKeepQueryParams(true); registry.addRedirectViewController(“/api/swagger-resources/configuration/ui”, “/swagger-resources/configuration/ui”); registry.addRedirectViewController(“/api/swagger-resources/configuration/security”, “/swagger-resources/configuration/security”); registry.addRedirectViewController(“/api/swagger-resources”, “/swagger-resources”); }

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

I have faced similar issue. My environment is Weblogic 12.2.1, Spring 4.3.3, Swagger 2.8.0, Guava 24.0-jre. I was trying all the whitelisting of swagger resources, etc.

Finally, got to know I overlooked the logs missing jackson jars version mismatch, as my server’s jackson took precedence.

fixed it with

       <wls:prefer-application-packages>
            <wls:package-name>com.fasterxml.jackson</wls:package-name>
        </wls:prefer-application-packages>

Now, Swagger is up and running.

Adding @EnableSwagger2 did the trick for me

I was running into the same issue. Once I allowed all access to <base-path>/swagger-resources/** I could access the API as normal. Looking with the dev-console of the browser, I realized that the swagger is NOT sending the Session/Credentials Information to the server, which causes the Server to return a 401. As swagger then misses the required information, it shows the “unable to infer baseurl” screen. However, as the correct base url again gives a 401, you end up in an endless loop.

Interestingly, for all other resources, the browser is sending the session/credential information. So I assume the bug is not on server side but swagger fails to send the (XMLHttp)Request to swagger-resources without the withCredentials flag set (https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials).

So for me the fix was to not require authentication/authorization for <base-path>/swagger-resources/** resources.

@dilipkrish thanks for the quick response. I’ve got a base url path (I think?) by defining the property springfox.documentation.swagger.v2.path. That seems to set the path for what would otherwise be /v2/api-docs, and also the base path for swagger-ui.html. That does not seem to change the base path for /swagger-resources/configuration/security though. That is still mapping to the root url, as is everything at the /swagger-resources path.

I think I’ve gotten everything working by adding a number of explicit redirects for urls that it’s unable to find because they are not mapped to that base path. The explicit redirects I’ve added are:

  • <base-path>/swagger-resources -> /swagger-resources
  • <base-path>/swagger-resources/configuration/security -> /swagger-resources/configuration/security
  • <base-path>/swagger-resources/configuration/ui -> /swagger-resources/configuration/ui
  • <base-path>/<base-path> -> <base-path> (this is a weird one)

I discovered this list of required redirects by watching the requests made by swagger-ui.html and seeing which were coming back as 404s. One particularly weird one is that it’s looking for the /v2/api-docs json at <base-path>/<base-path>, instead of just <base-path>.

Anyway, I think I have it working now.

Thanks for your help! And for supporting this library! It really is invaluable.

@skozlovich Your X-FORWARD headers would contain your upstream url.

For e.g. if you’re doing request path based routing in your api gateway

https://host/path -> https://upstream:port/

Then your X-Forward headers should reflect the upstream information

@dilipkrish what should the X-FORWARD headers contain? I can bring it up locally just fine, but when deploying behind a load balancer in AWS I get that dreaded “Unable to infer base url” popup