-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Customising the displayed base URL for API endpoints #963
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
Comments
It is not :) it uses the context path as the starting point. What you really need to is to define a dynamic servlet registration and create 2 dockets .. one for api and one for api/v2. This SO post might help ...
Dynamic servlet = servletContext.addServlet("v1Dispatcher", new DispatcherServlet(ctx1));
servlet.addMapping("/api");
servlet.setLoadOnStartup(1);
Dynamic servlet = servletContext.addServlet("v2Dispatcher", new DispatcherServlet(ctx2));
servlet.addMapping("/api/v2");
servlet.setLoadOnStartup(1); |
My apologies: it turns out I overlooked something ... the problem with this API is that it's a load of legacy code with hardly anyone remembering the why and how of design decisions made by developers who left two years ago ... :( . I overlooked the class-level RequestMapping annotations that exist in some controllers, splitting up the mapping path between them and the method-level RequestMapping annotations, for instance:
vs.
Additionally, the Spring configuration (including the Servlet registration) is rather opaque XML config, but I tracked the servlet mapping down to the web.xml level:
and, unfortunately, there still exists some legacy /v1 API code that we have to keep in working order. I assume then that this servlet mapping is what Swagger reads as its base path. Because one of my colleagues is rewriting the XML Spring configuration into a Java configuration, we can resolve the issue when that's in place. I'll just leave the base url as is for now, unless anybody knows of a way to tweak whatever Swagger reads as context path? Thanks for the insights! |
you're welcome! Feel free to update this if somethings not working right |
The method described above didn't really work for me. However, I was able to partition APIs based on version using a custom PathProvider in Springfox Swagger 2.4.0. Here is some sample code using a custom PathProvider that works: package my.package;
import org.joda.time.DateTime;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.util.UriComponentsBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.paths.AbstractPathProvider;
import springfox.documentation.spring.web.paths.Paths;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import static springfox.documentation.builders.PathSelectors.regex;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket latestDocumentationPlugin() {
return new VersionedDocket("latest");
}
@Bean
public Docket v10DocumentationPlugin() {
return new VersionedDocket("1.0");
}
class VersionedDocket extends Docket {
public VersionedDocket(String version) {
super(DocumentationType.SWAGGER_2);
super.groupName(version)
.select()
.apis(RequestHandlerSelectors.any())
.paths(regex("/api/" + version + "/.*"))
.build()
.apiInfo(getApiInfo(version))
.pathProvider(new BasePathAwareRelativePathProvider("/api/" + version))
.directModelSubstitute(DateTime.class, String.class)
.useDefaultResponseMessages(false)
.enableUrlTemplating(true);
}
private ApiInfo getApiInfo(String version) {
return new ApiInfo(
"Title", // title
"", // description
version,
"", // terms of service url
new Contact("Me","", "me@me.com"),
"", // licence
"" // licence url
);
}
}
class BasePathAwareRelativePathProvider extends AbstractPathProvider {
private String basePath;
public BasePathAwareRelativePathProvider(String basePath) {
this.basePath = basePath;
}
@Override
protected String applicationPath() {
return basePath;
}
@Override
protected String getDocumentationPath() {
return "/";
}
@Override
public String getOperationPath(String operationPath) {
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromPath("/");
return Paths.removeAdjacentForwardSlashes(
uriComponentsBuilder.path(operationPath.replaceFirst(basePath, "")).build().toString());
}
}
} |
What Din't work for you? |
The method you described with adding additional servlets and servlet mappings didn't work. Dynamic servlet = servletContext.addServlet("v1Dispatcher", new DispatcherServlet(ctx1));
servlet.addMapping("/api");
servlet.setLoadOnStartup(1);
Dynamic servlet = servletContext.addServlet("v2Dispatcher", new DispatcherServlet(ctx2));
servlet.addMapping("/api/v2");
servlet.setLoadOnStartup(1); The sample code I posted using a custom path provider works. |
Thanks, Sioulin. What you came up with works splendid! |
is there any way to specify base path in spring boot application similar to version
new ApiInfoBuilder()
.description(msgSource.getMessage("pi.description", null, LocaleContextHolder.getLocale()))
.termsOfServiceUrl("http://trvajjala.in")
.version("2.0")
.build();
|
@thirupathi-redpinesignals you can create your own PathProvider and register the bean |
Thanks Dilip, we have one requirement to implement OAuth2 Authentication using Spring boot similar to petstore.swagger.io reference site. With Authorize button top right corner. could you please provide document or reference source code for the sample application. |
public class BaseVersionProvider extends AbstractPathProvider {
public static final String ROOT = "/v2";
public BaseVersionProvider() {
super();
}
@Override
protected String applicationPath() {
return ROOT;
}
@Override
protected String getDocumentationPath() {
return ROOT;
}
}
return new Docket(DocumentationType.SWAGGER_2)
.groupName("wyzbee-api")
.apiInfo(apiInfo()).select()
.apis(RequestHandlerSelectors.basePackage(SiteResource.class.getPackage().getName()))
.build()
.pathProvider(baseVersionProvider()) but base_URL on swagger still showing "/" only |
@thirupathi-redpinesignals For what are you adding the base path. Can you curl/postman to that url with a base path of "/v2"? For e.g. yr service has a context path of |
Hi,
I'm trying to figure out whether it is possible to customise how our API endpoints vs. the base URL (basePath in JSON output) appears? For instance (how it appears in the Swagger UI):
hierarchical_records:
GET /v2/record/{collectionId}/{recordId}/ancestor-self-siblings.json
GET /v2/record/{collectionId}/{recordId}/children.json
GET /v2/record/{collectionId}/{recordId}/parent.json
GET /v2/record/{collectionId}/{recordId}/self.json
(...)
[ base url: /api , api version: 1.0 ]
... while we would like to present it like this:
hierarchical_records:
GET /record/{collectionId}/{recordId}/ancestor-self-siblings.json
GET /record/{collectionId}/{recordId}/children.json
GET /record/{collectionId}/{recordId}/parent.json
GET /record/{collectionId}/{recordId}/self.json
(...)
[ base url: /api/v2 , api version: 1.0 ]
I understand that the base_url annotation has been deprecated since Swagger 2.0, and I assume that Swagger retrieves the endpoint urls from the Spring @RequestMapping annotations.
However, we have @RequestMapping annotations in our controllers with URL's that include the /v2 bit:
@RequestMapping(value = "/v2/user/saveditem.json" (...)
but also some without it:
@RequestMapping(value = "/{collectionId}/{recordId}/parent.json" (...)
according to how things are set in the *mvc.xml Spring configuration.
Swagger (Springfox?) seems to be smart enough to figure this out by itself and present all endpoints with the same unified cut between base url and endpoint url, which makes me think that it should be possible to somehow influence the choice where that cut is made.
But how?
Thanks in advance!
Using Springfox 2.2.2 Swagger, Java 7, Spring 2.2.0 (no JAX-RS),
Project: https://github.com/europeana/api2/ (develop)
The text was updated successfully, but these errors were encountered: