Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

springfox-swagger-ui cannot find swagger-resources when run outside of spring boot #983

Closed
jmandawg opened this issue Sep 22, 2015 · 34 comments

Comments

@jmandawg
Copy link

Hi,

I'm running in springfox v2.2.2 inside JBoss. My dispatch serverlet looks like this:

          <servlet>
        <servlet-name>RestServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>RestServlet</servlet-name>
            <url-pattern>/restservices/*</url-pattern>
    </servlet-mapping>

And it works fine, and i can get to the swagger-resources from here:
http://localhost:8080/rootContext/restservices/swagger-resources

And i can view the api from here:
http://localhost:8080/rootContext/restservices/v2/api-docs

And Swagger-UI is accessable from here:
http://localhost:8080/rootContext/swagger-ui.html

The problem is when i load the http://localhost:8080/rootContext/swagger-ui.html page it is trying to access the swagger-resources from here:
http://localhost:8080/rootContext/swagger-resources

And they are not available. How can i fix this so that the swagger-ui.html either:

  1. looks in the right location (http://localhost:8080/rootContext/restservices/swagger-resources)
    or
  2. Swagger-ui.html is available at: http://localhost:8080/rootContext/restservices/swagger-ui.html

Thanks.

@dilipkrish
Copy link
Member

@jmandawg Hmmm the swagger-ui and swagger resource working together is predicated not the fact that they have the same context root. Unfortunately the way they are registered is different (resources vs. services) Wondering if you can create a servlet just for the swagger-resources to be at the same context path as the swagger-ui

@jmandawg
Copy link
Author

I'll give it a try, can you give any hints on how to do this? I searched around and can't find anything.

@dilipkrish
Copy link
Member

Not sure myself, may be something like this?

@jmandawg
Copy link
Author

Thanks for the tips, I was able to get it working by modifying the dispatcherServlet to listen on /* , but this prevented swagger-ui.html from being served. To fix this to let the swagger-ui.html bypass the dispatcherServlet i had to create a new servlet mapping:

           <servlet>
        <servlet-name>RestServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>default</servlet-name>
            <url-pattern>/swagger-ui.html</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>RestServlet</servlet-name>
            <url-pattern>/*</url-pattern>
    </servlet-mapping>

Also had to let the webjar through the dispatcher servlet:

<mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars/"/>

Kinda tricky to get working, but it works. Perhaps there is a better way to remap swagger-ui.html or let it pass through the dispatcherServlet.

Thanks again.

@dilipkrish
Copy link
Member

👍

@jmandawg
Copy link
Author

I figured out that adding <mvc:default-servlet-handler/> then i don't have to add the:

  <servlet-mapping>
    <servlet-name>default</servlet-name>
        <url-pattern>/swagger-ui.html</url-pattern>
  </servlet-mapping>

@dilipkrish
Copy link
Member

👍

@ankit2711
Copy link

@dilipkrish I have a similar issue with a spring-mvc and springfox integration. I can access
http://localhost:8080//v2/api-docs and it shows the big JSON with all my REST controllers scanned.
But when accessing http://localhost:8080//swagger-ui.html I get a 404 error.

I already have mvc:default-servlet-handler/ added in my servlet.xml file.

Below my configuration
servlet.xml
<mvc:resources mapping="swagger-ui.html" location="classpath:/META-INF/resources/" />
<mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars/" />
<mvc:default-servlet-handler />
<context:component-scan base-package="com.hi.cdi.v1.controller" />
<context:component-scan base-package="com.hi.cdi.hm.controller" />

SwaggerConfig.java
@EnableSwagger2
public class SwaggerConfig {
@bean
public Docket customImplementation() {
return new Docket(DocumentationType.SWAGGER_2);
}
}

applicationContext.xml has the swagger bean definition

NOTE: The project is not using Spring boot.

Would appreciate your help, already struggled for more than a day to get this working.

@alexeymatveevp
Copy link

What if I already have a DispatcherServlet, registered under another URL pattern like /services/* and I can't change this (because of my application architecture constraints)? How do I use swagger-ui in this case?
My spring controller service is located under:
http://localhost:8080/services/my-service
so my swagger docs are under
http://localhost:8080/services/v2/api-docs
and swagger-ui is installed using webjars under
http://localhost:8080/swagger-ui
because / is the context root of my application
So swagger-ui expects to see
http://localhost:8080/v2/api-docs
which are not there

The solution for me in this case is to change the swagger-ui query url to a custom one, because it cannot rely that swagger docs will be always under the same URL relatively. But how can I do that? Or maybe there is another solution?

@shollander
Copy link

@davidluckystar I had the same issue and I was able to get it working by mapping swagger-ui.html to the servlet path like this:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @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/");
  }
}

Then you should be able to access swagger at http://localhost:8080/services/swagger-ui.html

@alexeymatveevp
Copy link

@shollander Thanks a lot for your reply!
I will try it later - didn't know you can use double asterisk as a prefix **/swagger-ui.html in the url mapping. I guess the same you can do in XML if you have multiple DispatcherServlet's.

@alexeymatveevp
Copy link

Dear @shollander your solution is not working, here is the correct one:
registry.addResourceHandler("**/**").addResourceLocations("classpath:/META-INF/resources/");

@rsmogura
Copy link

rsmogura commented Aug 1, 2016

For those who use XML based configuration :)
<mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars/"/> <mvc:resources mapping="/swagger-ui.html" location="classpath:/META-INF/resources/swagger-ui.html"/>

@mandarnamdas
Copy link

mandarnamdas commented Oct 6, 2016

@dilipkrish In our project our Dispatcher servlet maps to ".do" with which Swagger does not working. But the moment I change it to "/" (/star) it does work. We have a requirement to keep servlet mapping to "*.do". Can you please suggest the way forward or send me example link where this kind of situation is handled. Thanks.

@dilipkrish
Copy link
Member

@mandarnamdas Not really sure how to do that, somehow you need to map the swagger resources differently.

@sumitit08
Copy link

sumitit08 commented Jul 20, 2017

@dilipkrish ... I am using springfox-swagger-ui with Spring boot and i am trying to do Api-Key authorization , i have gone through all the issues related to springfox-swagger-ui but still i am unable to find the solution.What changes i have made to achieve this is:

I have made all these changes to implement Api-Key security.

In SwaggerConfig class -

@Bean
    public Docket parkingReservationServiceApi() {
        return new Docket(DocumentationType.SWAGGER_2).select()
                .apis(RequestHandlerSelectors.basePackage(REST_PACKAGE_PATH))
                .paths(PathSelectors.regex("/c2creservation.*"))
                .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(true)
                .globalResponseMessage(RequestMethod.GET,
                    newArrayList(new ResponseMessageBuilder()
                        .code(500)
                        .message("500 message")
                        .responseModel(new ModelRef("Error"))
                        .build()))
                .apiInfo(getApiInfo())
                .securitySchemes(newArrayList(apiKey()))
                /*.securityContexts(newArrayList(securityContext()))*/
                .protocols(protocols())
				.securitySchemes(securitySchemes())
				.securityContexts(securityContexts());
    }
    
    private ApiKey apiKey() {
        return new ApiKey("abcdef12345", "api_key", "header");
    }
    
/*    private SecurityContext securityContext() {
        return SecurityContext.builder().securityReferences(defaultAuth())
                .forPaths(PathSelectors.regex("/c2creservation.*")).build();
    }*/

    List<SecurityReference> defaultAuth() {
       /* AuthorizationScope authorizationScope = new AuthorizationScope(
                "global", "accessEverything");*/
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[0];
//        authorizationScopes[0] = authorizationScope;
        return newArrayList(new SecurityReference("abcdef12345", authorizationScopes));
    }


	private List<SecurityContext> securityContexts() {
    	List<SecurityContext> securityContexts   = Arrays.asList(SecurityContext.builder().forPaths(PathSelectors.regex("/.*")).securityReferences(securityReferences()).build());
		return securityContexts;
	}

	private List<? extends SecurityScheme> securitySchemes() {
		 List<SecurityScheme> authorizationTypes = Arrays.asList(new ApiKey("api_key", "abcdef12345", "header"));
	      return authorizationTypes;
	}

	private Set<String> protocols() {
		Set<String> protocols = new HashSet<>();
		protocols.add("http");
		protocols.add("https");
		return protocols;
	}

IN Controller class:

@RestController
@Validated
@Api(value = "Search Parking Spaces", description = "Endpint for C2C Parking Reservation")
@SwaggerDefinition(securityDefinition = @SecurityDefinition(
		apiKeyAuthDefintions = {
				@ApiKeyAuthDefinition(key = "api_key", name = "abcdef12345", in = ApiKeyLocation.HEADER) 
		}
	)
)
@RequestMapping(value = "/v1")
public class ABCController extends BaseController
{
}

In swagger-ui.html

           function addApiKeyAuthorization() {
                var key = encodeURIComponent($('#input_apiKey')[0].value);
                if (key && key.trim() != "") {
                    var apiKeyAuth = new SwaggerClient.ApiKeyAuthorization("api_key", key, "header");
                    alert("apiKeyAuth:::"+apiKeyAuth);
                    alert("key:::"+key);
                    window.swaggerUi.api.clientAuthorizations.add(key, apiKeyAuth);
                    alert("added key " + key);
                }
            }

            $('#input_apiKey').change(addApiKeyAuthorization);

pom.xml

<dependency>
			<groupId>io.swagger</groupId>
			<artifactId>swagger-annotations</artifactId>
			<version>1.5.15</version>
		</dependency>

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

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

It would be appreciable if you will help me on this.

Thanks,
Sumit

@dilipkrish
Copy link
Member

What is the problem you're seeing @sumitit08

@gitforpushpak
Copy link

Hi @jmandawg / @dilipkrish , I am also facing same issue. My webservices are divided into two v1 and v2 versions. So there are two different servlets. I am implementing swagger for v2. From your comment I understand that you removed the "restservices" from /restservices/* and added

default
/swagger-ui.html

are you able to access http://localhost:8080/rootContext/restservices/swagger-ui.html ?
In my case I can not remove "restservices" from mapping.
Please suggest.

@dilipkrish
Copy link
Member

@gitforpushpak this is an old issue. The current version of the library is 2.7.0. So its likely older issues are no longer relevant or have been fixed if the issue is closed.

@tiddman
Copy link

tiddman commented Jan 18, 2018

I am having a variation of this issue using swagger 2.7.0.

Update, after a bunch of debugging I realized that having my SwaggerConfig in its own Spring profile causes this problem. I had this at the top of my SwaggerConfig class:

@Profile("swagger")

The reason for this is that the presence of swagger classes causes some of our unit tests to fail, so I wanted to put the swagger configuration in its own profile and exclude that from the unit tests.

However, this causes the problem described at the top of this ticket where swagger-ui.html works but /swagger-resources does not, but only when deployed in Tomcat (it works when run via bootRun). I suspect that this is either a sequencing problem in Spring initialization or some incompatibility between Swagger and Spring.

I'd like to leave this comment here in case anyone else runs into this problem if that's ok.

@dilipkrish
Copy link
Member

Thanks for the detailed explanation. I think it has to do with how the classloader loads the application context.

@iver3on
Copy link

iver3on commented Mar 31, 2018

local run no problem,but when i deployed on k8s . not working.
eg:
java.io.IOException: Unable to open root Jar file 'war:file:/app.jar*/BOOT-INF/lib/springfox-swagger-ui-2.6.1.jar'

@dilipkrish
Copy link
Member

@iver3on I don't know how k8s works, sorry.

@oeresundsgruppen
Copy link

springfox-swagger is truely so buggy that it needs a honest review and rewrite. tons of google-search shows problems.

@dilipkrish
Copy link
Member

@oeresundsgruppen if you're available to review and rewrite, this project could certainly use help.

@oeresundsgruppen
Copy link

Will gladly inform you of the findings once I get it work, have spend countless hours, and will start to look into your code...

@dilipkrish
Copy link
Member

Thanks great! Thanks for helping out @oeresundsgruppen

@oeresundsgruppen
Copy link

https://github.com/oeresundsgruppen/swaggerTest - now works in tomcat. Does springfox support old fashion servlets using @Api and @ApiOperation annotations ?

@oeresundsgruppen
Copy link

Got it working for old servlets with the appropriate annotations

@geektcp
Copy link

geektcp commented Dec 1, 2018

I found the really reason, because of @componentscan, and u must to annotate it , for example:
//@componentscan(basePackages = {"com.haizhi.dao","com.haizhi.controll","com.haizhi.service"})

and then , it will be ok, u can open the swagger-tui.html and /swagger-resources/configuration/ui

@geektcp
Copy link

geektcp commented Dec 1, 2018

swagger启动后,老是报错下面的url无法打开swagger-ui.html,
提示内部url无法打开swagger-resources/configuration/ui

原因是:
启用了组件扫描导致:@componentscan(basePackages = {"com.haizhi.dao","com.haizhi.controll","com.haizhi.service"})
这个问题真是费解。

解决办法:注释掉扫描注解即可:
//@componentscan(basePackages = {"com.haizhi.dao","com.haizhi.controll","com.haizhi.service"})

@ljrjain
Copy link

ljrjain commented Mar 20, 2019

Version 2.9.2 is not working on AWS ALB, it has same issue as mentioned by
it is still adding adding extra null...
/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/");
    }

@satishpatro44
Copy link

In my case, a swagger was opened in browser, somehow it was calling from that browser's opened swagger

I changed port & started it worked
So, remove all swagger url opened in browser
Not may be the case fot others

@ketan-barapatre-sarvaha

Just sharing my story, I was running into the same problem, during my attempt to implement Swagger UI, I stick to the official documentation to implement for non spring boot project, when I tried to add

default /swagger-ui.html

It did not work for me and I have a Java config project so no option to add below XML configuration

mvc:default-servlet-handler/

So, instead of mvc:default-servlet-handler/ I added

public class CustomMvcConfiguration extends WebMvcConfigurerAdapter {

_@Override
public void configureDefaultServletHandling(final DefaultServletHandlerConfigurer configurer) {
    configurer.enable();
}_

}

and it worked like charm.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests