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

Customizing swagger-ui.html location #1080

Closed
rockytriton opened this Issue Dec 2, 2015 · 31 comments

Comments

Projects
None yet
@rockytriton

rockytriton commented Dec 2, 2015

I've seen that we can customize the swagger api-docs location, i would also like to customize the location of swagger-ui.html and /configuration/ui, /configuration/security. I can't find anywhere to do this, is it possible?

@dilipkrish

This comment has been minimized.

Member

dilipkrish commented Dec 3, 2015

/configuration/ui and /configuration/security can't be changed unfortunately. Those are known locations to get this information. You could certainly change swagger-ui.html, if you're using spring-boot thats the default behavior, and you override that using an implementation of WebMvcConfigurerAdapter that adds your endpoint using the addResourceHandlers

@dilipkrish dilipkrish added the question label Dec 3, 2015

@dilipkrish dilipkrish added this to the 2.3.0 milestone Dec 3, 2015

@dilipkrish dilipkrish closed this Dec 5, 2015

@chornyi

This comment has been minimized.

Contributor

chornyi commented Jan 6, 2016

I was able to move Swagger UI under /documentation using this code.

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addRedirectViewController("/documentation/v2/api-docs", "/v2/api-docs");
    registry.addRedirectViewController("/documentation/configuration/ui", "/configuration/ui");
    registry.addRedirectViewController("/documentation/configuration/security", "/configuration/security");
    registry.addRedirectViewController("/documentation/swagger-resources", "/swagger-resources");
    registry.addRedirectViewController("/documentation", "/documentation/swagger-ui.html");
    registry.addRedirectViewController("/documentation/", "/documentation/swagger-ui.html");
}

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

However it still requires a redirect to /documentation/swagger-ui.html because the path name is hard-coded here: https://github.com/springfox/springfox/blob/master/springfox-swagger-ui/src/web/js/springfox.js#L4. Maybe this is something that could be improved.

@dilipkrish

This comment has been minimized.

Member

dilipkrish commented Jan 6, 2016

@chornyi 👍 thanks for the work-around... will chalk that up as a documentation enhancement

@dilipkrish dilipkrish reopened this Jan 6, 2016

@dilipkrish dilipkrish modified the milestones: 2.4.0, 2.3.0 Jan 6, 2016

@nedkoh

This comment has been minimized.

nedkoh commented Feb 8, 2016

Is this issue resolved? I want to be able to change to /api/ and will need this fix to make it work.

@dilipkrish

This comment has been minimized.

Member

dilipkrish commented Feb 8, 2016

@nedkoh there is nothing to resolve. Following @chornyi's instructions should help you. Just replace documentation with api

@nedkoh

This comment has been minimized.

nedkoh commented Feb 8, 2016

@dilipkrish I was referring to this part but did not realize the redirect is working as a workaround. Thanks. "However it still requires a redirect to /documentation/swagger-ui.html because the path name is hard-coded here: https://github.com/springfox/springfox/blob/master/springfox-swagger-ui/src/web/js/springfox.js#L4"

@dilipkrish

This comment has been minimized.

Member

dilipkrish commented Feb 8, 2016

@nedkoh oh I see. Sorry for the confusion! As a library that is pretty hard (and out of scope) to make configurable, which is why it is just tagged as a can-use-for-docs and will be documented as when you want to change this behavior, what should one do?

If you do see a way to make that easier would love feedback and a PR would be even better 😉

@nedkoh

This comment has been minimized.

nedkoh commented Feb 8, 2016

I had gotten it to work without redirect using the other swagger github project but it required some ugly .js manipulation of the static content and a JSP page which is not ideal. Will think of a cleaner solution. btw. I just tried the above and everything worked as expected.

@jeroenbellen

This comment has been minimized.

jeroenbellen commented Feb 19, 2016

Why is this issue closed? Redirecting is not a solution?
It should be possible to configure all endpoints to listen to a provided path.

@jeanchang22

This comment has been minimized.

jeanchang22 commented Jun 22, 2016

This fix doesn't work for groups, could you help to find a better solution for it?

@jeanchang22

This comment has been minimized.

jeanchang22 commented Jun 22, 2016

my projects have multiple versions of documents, on swagger-ui.html, there is a dropdown to link to different version of doc, however, after applying this fix, it always redirects to the first version of doc, the link to other versions of doc are no longer valid.

@gstaykov

This comment has been minimized.

gstaykov commented Apr 18, 2017

For version 2.6.1 if you want your groups to work too use this:

@Override
public void addViewControllers(ViewControllerRegistry registry) {
	registry.addRedirectViewController("/documentation/v2/api-docs", "/v2/api-docs").setKeepQueryParams(true);
	registry.addRedirectViewController("/documentation/swagger-resources/configuration/ui","/swagger-resources/configuration/ui");
	registry.addRedirectViewController("/documentation/swagger-resources/configuration/security","/swagger-resources/configuration/security");
	registry.addRedirectViewController("/documentation/swagger-resources", "/swagger-resources");
}

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

After that you can access the swagger-ui here: http://localhost:8080/documentation/swagger-ui.html

In this way the default group and the custom groups will work because of setKeepQueryParams(true) on the redirect. If you have custom path for the /v2/api-docs use it in the redirect ! For example if you have springfox.documentation.swagger.v2.path: /private/v2/api-docs for custom api-docs path your

registry.addRedirectViewController("/documentation/v2/api-docs", "/v2/api-docs").setKeepQueryParams(true);

should look like this:

registry.addRedirectViewController("/documentation/private/v2/api-docs", "/private/v2/api-docs").setKeepQueryParams(true);

This is still workaround. Enjoy

@dilipkrish

This comment has been minimized.

Member

dilipkrish commented Apr 18, 2017

Thanks @georgi-staykov for the useful tip!!

@sankarav

This comment has been minimized.

sankarav commented Jul 20, 2017

Thanks @chornyi for comments, it worked. But I am using spring websecurity in my application. In this case I had to do the following, so the requests related to swagger redirects get to the application.


@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

     @Override
      protected void configure(HttpSecurity http) throws Exception {
         http.authorizeRequests()
            .antMatchers(HttpMethod.GET, "/v2/api-docs").permitAll()
            .antMatchers(HttpMethod.GET,"/swagger-resources").permitAll()
            .antMatchers(HttpMethod.GET,"/configuration/**").permitAll()
            .antMatchers(HttpMethod.GET,"/documentation/**").permitAll()
            .antMatchers("/**").fullyAuthenticated()
            .and().csrf().disable();
      }
}

Is there a way I could modify your spring redirects/forwards to keep my security authorizations to minimum? I am expecting something like this, so everything under "/documentation/**" is authenticated for swagger-ui.


@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

     @Override
      protected void configure(HttpSecurity http) throws Exception {
         http.authorizeRequests()
            .antMatchers(HttpMethod.GET,"/documentation/**").permitAll()
            .antMatchers("/**").fullyAuthenticated()
            .and().csrf().disable();
      }
}

@dilipkrish

This comment has been minimized.

Member

dilipkrish commented Jul 21, 2017

I think you can get away with
.antMatchers(HttpMethod.GET,"/swagger-resources/**").permitAll()

@KD4

This comment has been minimized.

KD4 commented Dec 6, 2017

Is there no solution without redirecting? T_T

@dilipkrish

This comment has been minimized.

Member

dilipkrish commented Dec 6, 2017

@KD4 Solution to what?

@river226

This comment has been minimized.

river226 commented Mar 28, 2018

@dilipkrish The issue is that the only way to customize the url is a redirect. It would be nice if springfox had some built in way to make the necessary updates when it builds the swagger doc. Something like this:https://github.com/domaindrivendev/Swashbuckle#customizing-the-generated-swagger-docs without a need to actually redirect which is at best makeup on the pig that is this problem.

@dilipkrish

This comment has been minimized.

Member

dilipkrish commented Mar 28, 2018

@river226 You can customize the swagger description url. Its only a problem if you want your swagger-ui to be in a different place than the root of the context path.

The location of swagger-ui.html, the built in one, is like the north star for where all the other endpoints are located, ui configuration, security configuration, the different grouped swagger descriptions etc.

Im not familiar with swashbuckle, but what specifically of the customizations in swashbuckle are you expecting to see here? Could you perhaps provide an example of a proposed configuration? That will give me a better idea of the problem you're trying to solve with the makeup :)

@river226

This comment has been minimized.

river226 commented Mar 29, 2018

@dilipkrish Upon a second look, it looks like swashbuckle may not do what I was aiming for. What I and I am pretty sure most of the people in this thread are looking for is simply changing the north star. Instead of swagger-ui.html and make it say: "thisisuseful.whyisntthisathing". I find the idea as you posted previously that this is hard to make configurable doubtful at best, and setting up a workaround redirect is not a good solution to an obviously useful feature.

@dilipkrish

This comment has been minimized.

Member

dilipkrish commented Mar 29, 2018

@river226 Open to ideas

@bob9

This comment has been minimized.

bob9 commented Mar 31, 2018

I solved this problem by using rewrite rule..
add to dependancy

compile group: 'org.tuckey', name: 'urlrewritefilter', version: '4.0.4'

Make sure this component is in your @componentscan path

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
import org.tuckey.web.filters.urlrewrite.Conf;
import org.tuckey.web.filters.urlrewrite.UrlRewriteFilter;

import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import java.io.IOException;


@Component
public class MyUrlRewriteFilter extends UrlRewriteFilter {

    private static final String CONFIG_LOCATION = "classpath:/urlrewrite.xml";

    //Inject the Resource from the given location
    @Value(CONFIG_LOCATION)
    private Resource resource;

    //Override the loadUrlRewriter method, and write your own implementation
    @Override
    protected void loadUrlRewriter(FilterConfig filterConfig) throws ServletException {
        try {
            //Create a UrlRewrite Conf object with the injected resource
            Conf conf = new Conf(filterConfig.getServletContext(), resource.getInputStream(), resource.getFilename(), "@@yourOwnSystemId@@");
            checkConf(conf);
        } catch (IOException ex) {
            throw new ServletException("Unable to load URL rewrite configuration file from " + CONFIG_LOCATION, ex);
        }
    }
}

Rewrite rules xml put this in resources files name the file urlrewrite.xml.
Change /users/ to be whatever folder to want it to the rewrite rule to to navigate to.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 4.0//EN"
        "http://www.tuckey.org/res/dtds/urlrewrite4.0.dtd">
<urlrewrite>
    <rule>
        <from>/users/swagger-ui.html</from>
        <to type="passthrough">/swagger-ui.html</to>
    </rule>

    <rule>
        <from>/users/webjars/(.*)</from>
        <to type="passthrough">/webjars/$1</to>
    </rule>

    <rule>
        <from>/users/api-docs</from>
        <to type="passthrough">/api-docs</to>
    </rule>

    <rule>
    <from>/users/configuration/(.*)</from>
    <to type="passthrough">/configuration/$1</to>
    </rule>

    <rule>
    <from>/users/swagger-resources</from>
    <to type="passthrough">/swagger-resources</to>
</rule>
</urlrewrite>
@alfredyctan

This comment has been minimized.

alfredyctan commented Apr 4, 2018

The simplest way I found is extends some of the swagger builtin controller with new @RequestMapping
code: https://github.com/alfredyctan/afc/tree/master/afc-util/src/main/java/org/afc/swagger/docs, https://github.com/alfredyctan/example/tree/master/swagger/petstore-service

This allow parallel run with default and custom path swagger ui, at the end I can have this url running
base context - http://localhost:8080/petstore
actuator - http://localhost:8080/petstore/actuator
default swagger ui - http://localhost:8080/petstore/swagger-ui.html
custom swagger ui - http://localhost:8080/petstore/api/v2/docs/swagger-ui.html
API - http://localhost:8080/petstore/api/v2/user/login

@dilipkrish

This comment has been minimized.

Member

dilipkrish commented Apr 4, 2018

@alfredyctan and @bob9 those are both interesting approaches that seem to work. Thanks for sharing!

@river226

This comment has been minimized.

river226 commented Apr 5, 2018

@dilipkrish it would be awesome if one of these approaches were fully supported by the library and even better if they could be used with 1 or 2 additional lines of code.

@nahguam

This comment has been minimized.

nahguam commented Apr 16, 2018

Hi @dilipkrish ,

This is a feature that would also be useful for us. We have multiple apps, each with Swagger endpoints being exposed through Kubernetes Services and an AWS ALB Ingress. Each has to be on a separate endpoint. Up until now we've used the Spring Boot contextPath but due to another requirement we can no longer do that so we need another way to relocate the docs. Redirects will not cut it.

I've spent a little time having a look and have got it working by introducing a Swagger contextPath, that sits after the Spring Boot contextPath. I've started turning it into PR but wanted to get your input on the idea first.

master...nahguam:contextPath

@dilipkrish

This comment has been minimized.

Member

dilipkrish commented Apr 17, 2018

@nahguam Im going to preface by saying, Im not sure a generic solution that can be applied to this particular problem.

The swagger-ui that is bolted on to this library is only a convenience for the 80% of the use cases. For the remaining 20%, it may be better to not generalize and over-engineer a solution. Not that yours is, Im just expressing the philosophy behind the swagger-ui that is bundled in springfox.

Having said that I like you're idea. We could perhaps build on it so here is my feedback"

  • swagger-ui that is bundled is adheres to the web jar specification, so the default behavior is to register resource handlers automatically for spring boot apps.
  • EnableWebMvc is a total no-no when it comes to spring boot apps. It is a signal to tell spring boot you're going to manage your own configuration. A library like springfox shouldnt make that determination.
  • We just put considerable effort in removing dependence on RequestMappings with configuration expressions. This is so that we dont assume there is a PropertySourcesPlaceholderConfigurer

There is already a solution to let you aggregate swagger specifications from multiple services. Its used in projects like jhipster. That might be a thing you could consider.

@nahguam

This comment has been minimized.

nahguam commented Apr 17, 2018

Hi @dilipkrish,

This is great feedback, Thanks.

I haven't considered how to test this yet. Any pointers here?

Edit: I've had a bit more of a dig:

  • Re RequestMapping, I see you have PropertySourcedMapping which is used by PropertySourcedRequestMappingHandlerMapping. However this only scans methods, not types, so is unable to construct a new path if the mapping is on both the type and method, such as with ApiResourceController.
  • I see your point regarding EnableWebMvc and overriding the WebMvcConfigurer but I don't see another way to remap the webjar. I appreciate it would affect all webjars on the classpath. The intent there was that EnableWebMvc would only be enabled if a context path has been specified.

Just taking a step back, is it possible to aggregate swagger specs hosted on other servers? Is that what you meant by 'multiple services'?

@dilipkrish

This comment has been minimized.

Member

dilipkrish commented Apr 19, 2018

@nahguam as far as pointers on how to test, sadly it appears I punted testing PropertySourcedRequestMappingHandlerMapping :(

However this only scans methods, not types, so is unable to construct a new path if the mapping is on both the type and method, such as with ApiResourceController.

That is true. It was targeting a very simple use case of replacing the path without using PropertySourcesPlaceholderConfigurer

Just taking a step back, is it possible to aggregate swagger specs hosted on other servers? Is that what you meant by 'multiple services'?

It is totally possible. That is what I meant to say, sorry I wasnt clear. Yes, to clarify, you could have one endpoint that hosts swagger-ui (the springfox one) and it can aggregate services living in-the same app and/or in files or combine external swagger specifications in other services. You just need to implement your custom SwaggerResourcesProvider.

@zpf7879

This comment has been minimized.

zpf7879 commented Sep 10, 2018

My app is a Spring WebFlux app, and I tried all the approaches listed here in the thread. Unfortunately, none of them works in this context. I end up the following solution by using WebFilter (I personally feel not very gracefully but no better approach found yet).

@Component
public class SwaggerWebFilter implements WebFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getPath().pathWithinApplication().value();
        if (path.startsWith("/api/swagger-ui.html") || path.startsWith("/api/webjars")
                || path.startsWith("/api/api-docs") || path.startsWith("/api/configuration")
                || path.startsWith("/api/swagger-resources") || path.startsWith("/api/v2")) {
            exchange = exchange.mutate().request(request.mutate().path(path.substring(4)).build()).build();
        }
        return chain.filter(exchange);
    }
}
@n2696118

This comment has been minimized.

n2696118 commented Dec 7, 2018

It seems the only way to fix it (without resorting to redirects) to fork the repository and start renaming... Which resources would need to be changed for everything to work?

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