Multiple swagger-ui html pages in a spring application - spring

I am building an application where I would like to have two swagger urls:
http://localhost:8080/order-swagger.ui.html
http://localhost:8080/inventory-swagger.ui.html
I read many articles but did not find any solution.
What I found is that to define two docket beans but it does not effectively build two html pages. It creates 2 items in the upper right corner dropdown.
Much appreciated if you could provide how to do it.

Along with the two Docket beans, you could add a couple of URL redirection rules to route /order-swagger.ui.html and /inventory-swagger.ui.html to /swagger-ui.html with the correct group selected. I defined a WebMvcConfigurer bean to do the redirection and then I got the two separate URLs, http://localhost:8080/order-swagger.ui.html and http://localhost:8080/inventory-swagger.ui.html available showing the API definitions of /order and /inventory endpoints respectively. Bean definitions below:
#Bean
public Docket orderDocket() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("order")
.select().paths(path -> path.endsWith("/order"))
.build();
}
#Bean
public Docket inventoryDocket() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("inventory")
.select().paths(path -> path.endsWith("/inventory"))
.build();
}
#Bean
public WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addRedirectViewController("order-swagger.ui.html", "/swagger-ui.html?urls.primaryName=order");
registry.addRedirectViewController("inventory-swagger.ui.html", "/swagger-ui.html?urls.primaryName=inventory");
}
};
}

Related

How to redirect from #Controller to a flow

I need to redirect to a flow from a #Controller, but am not sure how to go about this. I need to either continue with MVC under a certain condition, or go into my flow under another condition. Here's the final line of my /auth method:
return new ModelAndView(isFlowProtected(getClientId(sessionDataPayloadJSON)) ?
"redirect:/login-flow" :
LoginConstants.LOGIN);
Essentially, I have two login flows, one through normal Spring MVC, one under webflow. Here's how I configured my flow:
#Bean
public FlowDefinitionRegistry flowRegistry() {
return getFlowDefinitionRegistryBuilder().addFlowLocation("/webflow/login-flow.xml","login-flow"
.setFlowBuilderServices(this.flowBuilderServices())
.build();
}
#Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(this.flowRegistry())
.build();
}
#Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder()
.setViewFactoryCreator(this.mvcViewFactoryCreator()) // Important!
.setValidator(this.localValidatorFactoryBean).build();
}
#Bean
public FlowHandlerMapping flowHandlerMapping() {
FlowHandlerMapping handlerMapping = new FlowHandlerMapping();
handlerMapping.setOrder(-1);
handlerMapping.setFlowRegistry(this.flowRegistry());
return handlerMapping;
}
#Bean
public FlowHandlerAdapter flowHandlerAdapter() {
FlowHandlerAdapter handlerAdapter = new FlowHandlerAdapter();
handlerAdapter.setFlowExecutor(this.flowExecutor());
handlerAdapter.setSaveOutputToFlashScopeOnRedirect(true);
return handlerAdapter;
}
#Bean
public ViewFactoryCreator mvcViewFactoryCreator() {
MvcViewFactoryCreator factoryCreator = new MvcViewFactoryCreator();
factoryCreator.setUseSpringBeanBinding(true);
return factoryCreator;
}
Assuming my path to my flow is correct, what am I doing wrong here? How can I redirect to the login-flow from my /auth endpoint when needed? I'm getting the following error currently:
java.io.FileNotFoundException: Could not open ServletContext resource [/webflow/login-flow.xml]
So maybe my path is wrong? The flow is inside of resources/webflow, so I think it's right, but maybe not?
Do you have a /webflow/login-flow.xml file in your WAR root directory? I think that's what that error indicates, that it can't find that file. I believe your redirect is working correctly, and your WebFlow configuration expects to find a flow configuration file at the location you specified, but it isn't finding it there.
I haven't used Java-based WebFlow configuration before, so I could be misunderstanding this, but best I read this, I think you might still need Flow xml files even when you do the rest of the configuration in Java.
See Configure Spring Web Flow with Java configuration

How set SpringFox to show two (or more) versions of the Rest API using Spring Boot?

I'm trying to figure out how manage two (or more) version of my API endpoints using Spring Fox.
To version my APIs, I'm using the Versioning through content negotiation, also know as Versioning using Accept header. The versions of each endpoint are controlled individually using the header information. Per example, for the version one I use the attribute produces:
#Override
#PostMapping(
produces = "application/vnd.company.v1+json")
public ResponseEntity<User> createUser(
For version two, I use:
#Override
#PostMapping(
produces = "application/vnd.company.v2+json",
consumes = "application/vnd.company.v2+json")
public ResponseEntity<User> createUserVersion2(
I not use consumes for the first (v1) version, so if the client use only application/json on the call the first version will be called by default.
I would like to show the two version on the Swagger UI. How to do that?
It's very simple. Just create one Docket for each version.
Example, the first version:
#Bean
public Docket customImplementation(
#Value("${springfox.documentation.info.title}") String title,
#Value("${springfox.documentation.info.description}") String description) {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo(title, description, "1.0"))
.groupName("v1")
.useDefaultResponseMessages(false)
.securitySchemes(newArrayList(apiKey()))
.pathMapping("/api")
.securityContexts(newArrayList(securityContext())).select()
.apis(e -> Objects.requireNonNull(e).produces().parallelStream()
.anyMatch(p -> "application/vnd.company.v1+json".equals(p.toString())))
.paths(PathSelectors.any())
.build();
}
And for version two:
#Bean
public Docket customImplementationV2(
#Value("${springfox.documentation.info.title}") String title,
#Value("${springfox.documentation.info.description}") String description) {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo(title, description, "2.0"))
.groupName("v2")
.select()
.apis(e -> Objects.requireNonNull(e).produces()
.parallelStream()
.anyMatch(p -> "application/vnd.company.v2+json".equals(p.toString())))
.build();
}
The secret here is filter the available endpoints by the produces attribute.
The Swagger-UI will show the two versions on the combo:
This code needs to be on a class annotated with #Configuration. You also need to enable the Swagger with #EnableSwagger2.
As mentioned by Dherik you can create Docket for each version. But to filter here I have tried using Predicate and custom controller annotations.
Configuration class annotated with #Configuration and #EnableSwagger2
import com.google.common.base.Predicate;
#Bean
public Docket apiV30() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("v30")
.select()
.apis(selectorV30())
.paths(PathSelectors.any()).build().apiInfo(apiEndPointsInfo());
}
private Predicate<RequestHandler> selectorV30(){
return new Predicate<RequestHandler>() {
#Override
public boolean apply(RequestHandler input) {
return input.findControllerAnnotation(SwaggerDocV30.class).isPresent();
}
};
}
#Bean
public Docket apiV31() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("v31")
.select()
.apis(selectorV31())
.paths(PathSelectors.any()).build().apiInfo(apiEndPointsInfo());
}
private Predicate<RequestHandler> selectorV31(){
return new Predicate<RequestHandler>() {
#Override
public boolean apply(RequestHandler input) {
return input.findControllerAnnotation(SwaggerDocV31.class).isPresent();
}
};
}
Custom Annotation class : SwaggerDocV30
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public #interface SwaggerDocV30 {
}
Custom Annotation class : SwaggerDocV31
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public #interface SwaggerDocV31 {
}
Finally annotate your controllers with #SwaggerDocV30 or #SwaggerDocV31
#SwaggerDocV30
#Controller
public class MyController extends AbstractController {}
Or
#SwaggerDocV31
#Controller
public class MyController extends AbstractController {}]

Support multiple pathmapping in Swagger UI/Spring boot

I am using swagger 2.0 in a Spring boot(version 1.5.9.RELEASE) project.
Swagger works fine but now documentation have hundreds of api and I want to redirect documentation on different different urls.I am having swagger configuration like blow.
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket postsApi() {
return new Docket(DocumentationType.SWAGGER_2).groupName("public-api")
.apiInfo(apiInfo()).select().paths(postPaths()).build();
}
private Predicate<String> postPaths() {
return or(regex("/api/posts.*"), or(regex("/api/.*"), regex("/secure/api/.*")));
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title("Swagger API")
.description("Swagger Integration with Spring Boot")
.termsOfServiceUrl(null)
.license(null)
.licenseUrl(null).version("1.0").build();
}
}
Please suggest any way. Thanks in advance.
Finally I break these api's into groups basis on their url as following code segment, creates three group one for Settings, another for Products and last one contains all the other documentation except settings and products.
#Bean
public Docket swaggerSettingsApi() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("Settings")
.select()
.apis(RequestHandlerSelectors.basePackage("com.xyz"))
.paths(regex("/secure/api/v1/settings/.*"))
.build()
.apiInfo(new ApiInfoBuilder().version("1.0").title("Settings API").build())
.globalOperationParameters(operationParameters());
}
#Bean
public Docket swaggerProductApi() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("Product")
.select()
.apis(RequestHandlerSelectors.basePackage("com.xyz.modules.v1"))
.paths(productPaths())
.build()
.apiInfo(new ApiInfoBuilder().version("1.0").title("Product API").build())
.globalOperationParameters(operationParameters());
}
#Bean
public Docket swaggerModuleApi() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("Others")
.select()
.apis(RequestHandlerSelectors.basePackage("com.xyz.modules.v1"))
.paths(postPaths())
.build()
.apiInfo(new ApiInfoBuilder().version("1.0").title("Other Modules API").build())
.globalOperationParameters(operationParameters());
}
private Predicate<String> postPaths() {
return or(regex("^(?=\\/secure\\/api\\/v1\\/)(?!.*(settings|products)).+\\/.*"));
}

Problems adding spring webflow to a spring boot and joinfaces application

I am trying to add webflow to a spring boot app using joinfaces library.
I am using primefaces-spring-boot-starter and jetty-spring-boot-starter to configure jetty server.
Added necessary webflow dependencies to pom and configured necessary flowregistry, flowbuilderservices, flowexecutor and flowhandlermapping, ...
The application start correctly, reads the flows definitions from xmls and if enter to a flow via url the decision states are running correctly, reads the corresponding view state .xhtml file, calls the managed bean methods, and all are working apparently well.
But... once finished executing bean methods, when I hope to html be rendered in browser, the application is redirected to app root folder without any error in the log.
I have this behavior with all the flows of the application. Bean methods are executed correctly and when I hope to see the html... redirected to root.
Anyone tried to add webflow to a joinfaces jsf application successfully? I am missing to override some default configuration of joinfaces?
Thanks.
public class MvcConfiguration implements WebMvcConfigurer {
#Autowired
private WebFlowConfiguration webFlowConfiguration;
#Bean
public FlowHandlerMapping flowHandlerMapping() {
FlowHandlerMapping handlerMapping = new FlowHandlerMapping();
handlerMapping.setOrder(-1);
handlerMapping.setFlowRegistry(this.webFlowConfiguration.flowRegistry());
return handlerMapping;
}
#Bean
public FlowHandlerAdapter flowHandlerAdapter() {
JsfFlowHandlerAdapter adapter = new JsfFlowHandlerAdapter();
adapter.setFlowExecutor(this.webFlowConfiguration.flowExecutor());
return adapter;
}
#Bean
public ViewResolver faceletsViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setViewClass(JsfView.class);
resolver.setPrefix("/");
resolver.setSuffix(".xhtml");
return resolver;
}
}
#Configuration
public class WebFlowConfiguration extends AbstractFacesFlowConfiguration {
#Bean
public FlowDefinitionRegistry flowRegistry() {
return getFlowDefinitionRegistryBuilder()
.setBasePath("classpath*:/META-INF/resources/flows")
.addFlowLocationPattern("/**/*.xml")
.setFlowBuilderServices(flowBuilderServices())
.build();
}
#Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder()
.setDevelopmentMode(true)
.setViewFactoryCreator(new JsfViewFactoryCreator())
.build();
}
#Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(flowRegistry())
.addFlowExecutionListener(new FlowFacesContextLifecycleListener())
.addFlowExecutionListener(new SecurityFlowExecutionListener())
.setMaxFlowExecutionSnapshots(0)
.build();
}
}

How to set host url for springfox (more exact springfox-swagger2) in spring-mvc?

I have spring-mvc app and I've embed RestAPI in. All works correctly my rest api is mapped on /rest/* url. When I added SwaggerConfig it had started to recognise my controllers, but when I tried it out in swagger-ui (gui form to simplify consumers interaction with api)
I've got 404 not found status. Because this tried it out on
this doesnt do request on valid url
http://localhost:8080/ProductCatalog/rest/branch?id=1
although SwaggerConfig is mapped on correct url, because I've got this GUI representation when write
http://localhost:8080/ProductCatalog/rest/swagger-ui.html
There is a main part of app on root url (this isn't part in which i work) my part is mapped on /rest/*
How can I change this "try it out" url on /rest/* too?
My SwaggerConfig
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket pscApi() {
return new Docket(DocumentationType.SWAGGER_2)
//.groupName("PSC");
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("restService.com.websystique.springmvc"))
.paths(PathSelectors.any())
.build();
//PathSelectors.regex("/api/.*")
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("RestApiOfPSC")
.description("REST API for PSC.")
.build();
}
}
and I've specified this too
#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/");
}
Sorry for my bad english and thanks in advance
I've got how to do this.
docket.pathMapping("/rest");
and sometimes you need to change it another way
in your Docket bean write docket.host("your host url");
more exactly read my issue
https://github.com/springfox/springfox/issues/1468
and go through the reference #issue1050 too.

Resources