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
Closed

Comments

@jmandawg
Copy link

@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
Copy link
Member

@dilipkrish 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
Copy link
Author

@jmandawg 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
Copy link
Member

@dilipkrish dilipkrish commented Sep 23, 2015

Not sure myself, may be something like this?

@jmandawg
Copy link
Author

@jmandawg 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
Copy link
Member

@dilipkrish dilipkrish commented Sep 23, 2015

👍

@jmandawg
Copy link
Author

@jmandawg 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
Copy link
Member

@dilipkrish dilipkrish commented Sep 23, 2015

👍

@ankit2711
Copy link

@ankit2711 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
Copy link

@davidluckystar 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
Copy link

@shollander 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
Copy link

@davidluckystar 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
Copy link

@davidluckystar 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
Copy link

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

@dilipkrish dilipkrish commented Oct 6, 2016

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

@sumitit08
Copy link

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

@dilipkrish dilipkrish commented Jul 28, 2017

What is the problem you're seeing @sumitit08

@gitforpushpak
Copy link

@gitforpushpak 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
Copy link
Member

@dilipkrish 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
Copy link

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

@dilipkrish 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
Copy link

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

@dilipkrish dilipkrish commented Apr 3, 2018

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

@oeresundsgruppen
Copy link

@oeresundsgruppen 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
Copy link
Member

@dilipkrish dilipkrish commented Nov 7, 2018

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

@oeresundsgruppen
Copy link

@oeresundsgruppen 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
Copy link
Member

@dilipkrish dilipkrish commented Nov 12, 2018

Thanks great! Thanks for helping out @oeresundsgruppen

@oeresundsgruppen
Copy link

@oeresundsgruppen 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
Copy link

@oeresundsgruppen oeresundsgruppen commented Nov 19, 2018

Got it working for old servlets with the appropriate annotations

@geektcp
Copy link

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

@satishpatro44 satishpatro44 commented Sep 11, 2019

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
Linked pull requests

Successfully merging a pull request may close this issue.

None yet