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 · 31 comments

Comments

Projects
None yet
@jmandawg

jmandawg commented Sep 22, 2015

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

This comment has been minimized.

Member

dilipkrish commented Sep 23, 2015

@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

This comment has been minimized.

jmandawg commented Sep 23, 2015

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

This comment has been minimized.

Member

dilipkrish commented Sep 23, 2015

Not sure myself, may be something like this?

@jmandawg

This comment has been minimized.

jmandawg commented Sep 23, 2015

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

This comment has been minimized.

Member

dilipkrish commented Sep 23, 2015

👍

@jmandawg

This comment has been minimized.

jmandawg commented Sep 23, 2015

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

This comment has been minimized.

Member

dilipkrish commented Sep 23, 2015

👍

@ankit2711

This comment has been minimized.

ankit2711 commented Nov 17, 2015

@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.

@davidluckystar

This comment has been minimized.

davidluckystar commented Feb 9, 2016

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

This comment has been minimized.

shollander commented Feb 11, 2016

@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

@davidluckystar

This comment has been minimized.

davidluckystar commented Feb 12, 2016

@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.

@davidluckystar

This comment has been minimized.

davidluckystar commented Feb 13, 2016

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

@rsmogura

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

Member

dilipkrish commented Oct 6, 2016

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

@sumitit08

This comment has been minimized.

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

This comment has been minimized.

Member

dilipkrish commented Jul 28, 2017

What is the problem you're seeing @sumitit08

@gitforpushpak

This comment has been minimized.

gitforpushpak commented Dec 30, 2017

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

This comment has been minimized.

Member

dilipkrish commented Jan 2, 2018

@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

This comment has been minimized.

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

This comment has been minimized.

Member

dilipkrish commented Jan 30, 2018

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

@iver3on

This comment has been minimized.

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

This comment has been minimized.

Member

dilipkrish commented Apr 3, 2018

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

@oeresundsgruppen

This comment has been minimized.

oeresundsgruppen commented Oct 28, 2018

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

@dilipkrish

This comment has been minimized.

Member

dilipkrish commented Nov 7, 2018

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

@oeresundsgruppen

This comment has been minimized.

oeresundsgruppen commented Nov 9, 2018

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

This comment has been minimized.

Member

dilipkrish commented Nov 12, 2018

Thanks great! Thanks for helping out @oeresundsgruppen

@oeresundsgruppen

This comment has been minimized.

oeresundsgruppen commented Nov 18, 2018

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

@oeresundsgruppen

This comment has been minimized.

oeresundsgruppen commented Nov 19, 2018

Got it working for old servlets with the appropriate annotations

@geektcp

This comment has been minimized.

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

This comment has been minimized.

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"})

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