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

Can basePath be set to webapp context? #64

Closed
thomaschristensen opened this issue Apr 27, 2013 · 13 comments
Closed

Can basePath be set to webapp context? #64

thomaschristensen opened this issue Apr 27, 2013 · 13 comments
Labels

Comments

@thomaschristensen
Copy link

The documented way to set up the SwaggerConfiguration bean is to hardcode the basePath. Is there a way to pick up the current webapp context instead?
I understand that when finally publishing it would be better to use properties, since public URL isn't necessarily the same as the webapps deployed context (proxies in front etc).

@dilipkrish
Copy link
Member

@thomaschristensen Its not really hard coded, its a configured property :). Having said that, I havent found a good way to infer the path (including the scheme, hostname and port) in spring mvc. This is a problem I'd like to see solved as well.

Within a corporate network we have the ability to hit the documentation endpoint in a fully qualified domain name or just the machine name (depending on how the web server is set up)

for e.g. the documentation for services on a machine called machine1 in a companya.com can be reached using either of these locations

http://machine1/api-docs
https://machine1/api-docs
http://machine1.companya.com/api-docs
https://machine1.companya.com/api-docs

It would be nice to infer those rather than "hard-coding" the basePath.

@aliaksei-lithium
Copy link

@thomaschristensen @dilipkrish
I found another solution:
in context only set:

 <bean id="swaggerConfiguration" class="com.mangofactory.swagger.SwaggerConfiguration">
        <property name="apiVersion" value="1.0"/>
        <property name="basePath" value="/rest/"/>
        <property name="extensions">
           ....
        </property>
    </bean>

then, in swagger-ui.js:

var url =  window.location.href.match(/.*\/rest/g);
 $(function () {
     window.swaggerUi = new SwaggerUi({
                discoveryUrl: url + '/api-docs',

and finally add in some places where base path need in swagger.js:

 if (this.basePath.match(/^HTTP/i) === null) {
                this.basePath = window.location.href.match(/.*(?=\/rest)/)+this.api.basePath;
            }

Yes, /rest/ is hardocoded, but now it's ok for us

@dilipkrish
Copy link
Member

@Daigotsu Thanks thats pretty useful!

@dilipkrish
Copy link
Member

This will be addressed when issue #95 is fixed

@katiaSouza
Copy link

@Daigotsu Hi, I'm trying use your solution for get dynamic basePath, but I when deploy my application occurr above error:

[Thu Jul 2013 12:55:38.337] ERROR [] (org.springframework.web.servlet.DispatcherServlet:468) - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'swaggerConfiguration' defined in URL [file:/home/katia/juno-workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp1/wtpwebapps/CorporateServicesWeb/WEB-INF/classes/spring-servlet.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.mangofactory.swagger.SwaggerConfiguration]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.mangofactory.swagger.SwaggerConfiguration.()
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1011)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:957)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:490)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
    at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:652)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:600)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:666)
    at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:519)
    at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:460)
    at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
    at javax.servlet.GenericServlet.init(GenericServlet.java:160)
    at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1189)
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1103)
    at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1010)
    at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4935)
    at org.apache.catalina.core.StandardContext$3.call(StandardContext.java:5262)
    at org.apache.catalina.core.StandardContext$3.call(StandardContext.java:5257)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
    at java.lang.Thread.run(Thread.java:662)
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.mangofactory.swagger.SwaggerConfiguration]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.mangofactory.swagger.SwaggerConfiguration.()
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:83)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1004)
    ... 28 more
Caused by: java.lang.NoSuchMethodException: com.mangofactory.swagger.SwaggerConfiguration.()
    at java.lang.Class.getConstructor0(Class.java:2715)
    at java.lang.Class.getDeclaredConstructor(Class.java:1987)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:78)
    ... 29 more

Can you help me?

@katiaSouza
Copy link

@Daigotsu Hello, I made a little modification in your bean swaggerConfiguration, I changed tag property for construct-args:

        
                
    

And the error message changed:

[Thu Jul 2013 14:30:46.118] ERROR [] (org.springframework.web.servlet.DispatcherServlet:468) - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'swaggerConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.mangofactory.swagger.DocumentationTransformer com.mangofactory.swagger.SwaggerConfiguration.documentationTransformer; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mangofactory.swagger.DocumentationTransformer] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:288)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1120)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:522)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
    at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:652)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:600)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:666)
    at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:519)
    at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:460)
    at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
    at javax.servlet.GenericServlet.init(GenericServlet.java:160)
    at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1189)
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1103)
    at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1010)
    at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4935)
    at org.apache.catalina.core.StandardContext$3.call(StandardContext.java:5262)
    at org.apache.catalina.core.StandardContext$3.call(StandardContext.java:5257)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
    at java.lang.Thread.run(Thread.java:662)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.mangofactory.swagger.DocumentationTransformer com.mangofactory.swagger.SwaggerConfiguration.documentationTransformer; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mangofactory.swagger.DocumentationTransformer] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:514)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:285)
    ... 28 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mangofactory.swagger.DocumentationTransformer] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:967)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:837)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:749)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486)
    ... 30 more

Can you help me?

@dilipkrish
Copy link
Member

@katiaSouza If you copied that configuration snippet, that solution will not work for 0.5.x version. You'd need to create an subclass of the ExtensibilityModel and change the base path in the swaggerConfiguration.

@aliaksei-lithium
Copy link

@katiaSouza @dilipkrish Sorry for late answer. Yeah check new version of swagger. Cause first solution i use in 0.4 version.
Here my config now:
swagger-context.xml (/rest/v2 - mapping for servlet)

<mvc:resources location="classpath:/swagger/v2/" mapping="/api/**"/>

    <context:property-placeholder location="classpath:swagger-v2.properties" />

    <bean id="localeResolver" class="org.springframework.web.servlet.i18n.FixedLocaleResolver">
        <property name="defaultLocale" value="en"/>
    </bean>

    <bean id="documentationConfigV2" class="com.XXX.workload.v2.rest.swagger.config.CustomDocumentationConfig">
    </bean>

    <bean id="extensibilityModule" class="com.XXX.workload.v2.rest.swagger.config.CustomExtensibilityModule" />

swagger-v2.properties

documentation.services.basePath = /rest/v2/
documentation.services.version = 2

CustomExtensibilityModule.java

@Configuration
@Import(DocumentationConfig.class)
public class CustomDocumentationConfig {

    @Bean
    public NameEndPointComparator endPointComparator() {
        return new NameEndPointComparator();
    }

    @Bean
    public NameOperationComparator operationComparator() {
        return new NameOperationComparator();
    }

    @Bean
    public SwaggerConfiguration swaggerConfigurationV2(DefaultConfigurationModule defaultConfig,
                                                     ExtensibilityModule extensibility, @Value("${documentation.services.basePath}") String basePath,
                                                     @Value("${documentation.services.version}") String apiVersion) {
        SwaggerConfiguration swaggerConfiguration = new SwaggerConfiguration(apiVersion, basePath);
        return extensibility.apply(defaultConfig.apply(swaggerConfiguration));
    }

    @Bean
    public DocumentationControllerV2 documentationControllerV2() {
        return new DocumentationControllerV2();
    }

from api.html

  var url =  window.location.href.match(/.*\/rest/g);
    $(function () {
        window.swaggerUi = new SwaggerUi({
                discoveryUrl: url + '/v2/api-docs',
                apiKey:"",
                dom_id:"swagger-ui-container",
                supportHeaderParams: true,
                supportedSubmitMethods: ['get', 'post', 'put', 'delete'],
                onComplete: function(swaggerApi, swaggerUi){
            if(console) {
                        console.log("Loaded UPSA REST UI")
                        console.log(swaggerApi);
                        console.log(swaggerUi);
                    }
                  $('pre code').each(function(i, e) {hljs.highlightBlock(e)});
                },
                onFailure: function(data) {
            if(console) {
                        console.log("Unable to Load UPSA REST UI");
                        console.log(data);
                    }
                },
                docExpansion: "none"
            });

            window.swaggerUi.load();
        });

from swagger.js()

~~~~~~50 line

SwaggerApi.prototype.build = function() {
            var _this = this;
            this.progress('fetching resource list: ' + this.discoveryUrl);
            return jQuery.getJSON(this.discoveryUrl, function(response) {
                var res, resource, _i, _j, _len, _len1, _ref, _ref1;
                if (response.apiVersion != null) {
                    _this.apiVersion = response.apiVersion;
                }
/*HERE ------->>>>
                if ((response.basePath != null) && jQuery.trim(response.basePath).length > 0) {
                    _this.basePath = response.basePath;
               //add config, to define only last part of url in spring application context.
               //sdfsdfsdf
            if (_this.basePath.match(/^HTTP/i) === null) {
                _this.basePath = window.location.href.match(/.*(?=\/rest)/) + response.basePath;
            }
                    if (_this.basePath.match(/^HTTP/i) == null) {
                        _this.fail("discoveryUrl basePath must be a URL.");
                    }
                    _this.basePath = _this.basePath.replace(/\/$/, '');
                } else {
                    _this.basePath = _this.discoveryUrl.substring(0, _this.discoveryUrl.lastIndexOf('/'));
                    log('derived basepath from discoveryUrl as ' + _this.basePath);
                }

~~~~200 line
 SwaggerResource = (function() {

        function SwaggerResource(resourceObj, api) {
            var parts,
                _this = this;
            this.api = api;
            this.path = this.api.resourcePath != null ? this.api.resourcePath : resourceObj.path;
            this.description = resourceObj.description;
            parts = this.path.split("/");
            this.name = parts[parts.length - 1].replace('.{format}', '');
            this.basePath = this.api.basePath;
            this.operations = {};
            this.operationsArray = [];
            this.modelsArray = [];
            this.models = {};
/*HERE ------->>>>
            //add config, to define only last part of url in spring application context.
            if (this.basePath.match(/^HTTP/i) === null) {
                this.basePath = window.location.href.match(/.*(?=\/rest)/)+this.api.basePath;
            }

~~~600 line
 SwaggerOperation.prototype.urlify = function(args, includeApiKey) {
            var param, queryParams, reg, url, _i, _len, _ref;
            if (includeApiKey == null) {
                includeApiKey = true;
            }
/*HERE ------->>>>
            url = window.location.href.match(/.*(?=\/rest)/) + this.resource.basePath + this.pathJson();
            _ref = this.parameters;
            for (_i = 0, _len = _ref.length; _i < _len; _i++) {
                param = _ref[_i];
                if (param.paramType === 'path') {
                    if (args[param.name]) {
                        reg = new RegExp('\{' + param.name + '[^\}]*\}', 'gi');
                        url = url.replace(reg, encodeURIComponent(args[param.name]));
                        delete args[param.name];
                    } else {
                        throw "" + param.name + " is a required path param.";
                    }
                }
            }

@friscoMad
Copy link
Contributor

Swagger Spec 1.2 changes the Resource Listing so basePath is no longer required and all api paths are relative to Resource Listing path so this will fix our issue and simplify everything.

This change seem to be included in Swagger 1.3 that is at RC2 so maybe an early adoption will be enough to close this issue.

@katiaSouza
Copy link

@Daigotsu Hi, I applied the modification suggested by you in my application and it works very well.
Thanks by reply me.
@dilipkrish Thank very much!!!

@friscoMad
Copy link
Contributor

As said #128 Should fix this one also.
Linking just for reference.

@adrianbk
Copy link
Member

@boeboe can you share your spring configuration and we can try help.

@boeboe
Copy link

boeboe commented Nov 17, 2014

@adrianbk

I was able to change the basePath as mentioned in #484 .

Thanks!

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

No branches or pull requests

7 participants