Initialize swagger without web.xml to disable it in production - rest

I am using Swagger with Jersey 2 and spring bootstrap. Currently I'm looking a solution to disable swagger on production as it will be concern in case any user
uses the API's with the swagger UI.
I'm registering io.swagger.jersey.config.JerseyJaxrsConfig servlet in web.xml and passing init parameters to it like api.version and swagger.api.basepath. Along with this I'm registering package to scan as io.swagger.jaxrs.listing so that org.glassfish.jersey.server.ResourceConfig will take care to prepare swagger UI.
I got to know from internet that we can achive this byb using #profile annotations. But I experienced that If we register any class in Web.xml, even though you are using #Profile on that class level, it will not work as the class going to be loaded at context load.
I have static contents in my project like swagger-ui-min.js, swagger-ui.js, index.html etc to load the swagger.
With this setup, how can I disable swagger UI in production? Also if some one have experience on , should swagger could be disabled in production or not?

You could have a flag which allows to load the Swagger Servlet only when you are not in production (here for Swagger 2):
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import java.util.HashSet;
import java.util.Set;
import io.swagger.jaxrs2.integration.resources.OpenApiResource;
#ApplicationPath("") // no application path after the context root
public class MyApp extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<>();
classes.add(...); // your main service
if (notInProduction) { // a flag telling that you are not in production
classes.add(OpenApiResource.class);
}
return classes;
}
}

Below code worked for me.
String enable_swagger_ui = System.getenv("ENABLE_SWAGGER_UI");
if( enable_swagger_ui != null && enable_swagger_ui.equalsIgnoreCase("true"))
packages("io.swagger.jaxrs.listing");
You just need to add the ENABLE_SWAGGER_UI in system environment variable where you want to enable swagger.

Related

Keycloak: Add custom extension io.undertow.servlet.ServletExtension

I wanted to add a custom servlet extension to Keycloak which would install a http handler that gets invoked on every request sent to Keycloak and sets up some logging MDC context that our custom SPI code can use for logging the incoming request traces correctly.
Following the docs here I created a custom extension class:
public class UndertowHandlerExtension implements ServletExtension {
#Override
public void handleDeployment(DeploymentInfo deploymentInfo, ServletContext servletContext) {
deploymentInfo.addInnerHandlerChainWrapper(TraceIdCapturingHandler::new);
}
}
And have defined my custom http handler TraceIdCapturingHandler in the same JAR file. I also added a file to META-INF/services/io.undertow.servlet.ServletExtension and set the fully qualified reference to the extension class. I also updated my deployments jboss-deployment-structure.xml and added the following 2 entries as dependencies:
<module name="io.undertow.servlet" />
<module name="javax.servlet.api" />
However, when my deployment is created the extension is not being invoked and my filter is not executing. Is there something I am missing in terms of how to configure Wildfly for Keycloak so that my extension and handler are installed and used correctly?
EDIT:
After doing a bit of digging I realized I was headed down the wrong path. Looked at this repository and I think I need a custom RealResourceProvider as shown here which in turn can install my filter by obtaining an instance of ResteasyProviderFactory and invoking getContainerRequestFilterRegistry().registerSingleton().
Will try this out and report back.
Please see the edit above for my question. I was able to implement a RealmResourceProviderFactory instance that initialized the filters I needed on startup in the init() method:
#Override
public void init(Config.Scope scope) {
log.info("Initializing");
initializeKeycloakFilters();
}
private void initializeKeycloakFilters() {
ResteasyProviderFactory providerFactory = ResteasyProviderFactory.getInstance();
TraceIdCapturingFilter filter = new TraceIdCapturingFilter();
providerFactory.getContainerRequestFilterRegistry().registerSingleton(filter);
}

open-liberty and openapi(/ui) and "no operations defined in spec!"

I can not find out why my rest api endpoints are not visible / executable in openapi/ui with openliberty. openapi/ui reports "there are no operations defined in spec!" My project consists of an empty application class and a trivial rest controller with a single endpoint:
package sandbox.io.rest;
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;
#ApplicationPath("/api")
public class RestApplication extends Application { }
package sandbox.io.rest;
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Response;
#ApplicationScoped
public class RestController
{
#GET
#Path("/system/properties")
#Produces(APPLICATION_JSON)
public Response getSystemProperties()
{
return Response.ok(System.getProperties()).build();
}
}
I have the following features activated in my server.xml:
<featureManager>
<feature>jakartaee-9.1</feature>
<feature>microProfile-5.0</feature>
<!-- <feature>restfulWS-3.0</feature> -->
<!-- <feature>jsonp-2.0</feature> -->
<!-- <feature>jsonb-2.0</feature> -->
<!-- <feature>cdi-3.0</feature> -->
<!-- <feature>mpConfig-3.0</feature> -->
<!-- <feature>mpRestClient-3.0</feature> -->
<!-- <feature>mpOpenAPI-3.0</feature> -->
</featureManager>
Everything was generated from openliberty/get started.
There is a real minimal reproducer here.
I also played around with activation of mpOpenAPI-3.0 feature but could not make it work. Could anybody have a look at the reproducer please?
BTW: Please don't get irritated by the repo name, it's just that I try to set up an environment for openliberty, hibernate and postgres ... However I'd like to use openapi/ui, too.
In addition to Scott Kurz's answer: https://stackoverflow.com/a/71946440/8067386
The reason OpenAPI isn't finding the endpoint is because without the #PATH annotation (or #Provider) your RestController class is not being registered with the JAX-RS runtime. An older way to register would be to return RestController.class from RestApplication.getClasses(). However, this is less dynamic than annotating your endpoint class.
You can fix this by adding a class-level #Path annotation. To keep the aggregate URL path the same you can do #Path("/") so:
#Path("/")
#ApplicationScoped
public class RestController
{
#GET
#Path("/system/properties")
#Produces(APPLICATION_JSON)
public Response getSystemProperties()
{
return Response.ok(System.getProperties()).build();
}
}
I believe this is more a Jakarta RESTful issue than an MicroProfile OpenAPI issue as it turns out.

Questions about combining Hystrix with Feign

I am trying to use the new HystrixFeign support in Feign. Here is what my code looks like
route66Client =
HystrixFeign.builder()
.logger(new Slf4jLogger())
.encoder(new GsonEncoder())
.target(Route66Client.class, "http://route66/");
The Route66Client is defined as
public interface Route66Client {
#RequestLine("POST /route")
ApiResponse getRoute(
RouteRequest request);
}
When i try to run the code. I get UnknownHostException. As it is not able to resolve route66 for its hostname. Anyone knows what i could be missing ?
Further i had this working with regular Feign ( not HystrixFeign ). All i did was to annotate my Route66Client class with #FeignClient("...") and then injecting Route66Client in the calling class ( So no Feign.builder() was used )
But i couldn't find some #HystrixFeignClient annotation. So i went ahead and started using the HystrixFeign.builder(). But then when i did that the serviceName->Address resolution stopped working.
If you want the benefits of eureka, don't use the builder directly. Put #EnableFeignClients on an #Configuration class (usually your application). Then label Route66Client with #FeignClient("route66") and inject Route66Client. This is only available in Brixton's 2nd Milestone. See the documentation.

Creating a Spring 4 MVC project with annotations and no xml files

I'm new to Spring MVC and Hibernate. I'm trying to start a project by following tutorials but I have been running into problems as my project structure is not consistent with the tutorials I am reading.
I have downloaded the latest STS and I do see the option of creating an Spring MVC project. However it is based on Spring 3 and still uses XML files. From what I have read it looks like there is a way to do it without XML files since Spring 3. I prefer annotations over XML files greatly.
How can I create a Spring MVC 4 application that is based on annotations and relies on xml files minimally?
EDIT:
I want to create a web project
Here is a squeletal example of full java configuration. You will need :
a class extending AbstractAnnotationConfigDispatcherServletInitializer to replace the old web.xml file
one or more #Configuration annotaded class(es) to initialize the root context (replaces the old applicationContext.xml)
one or more #Configuration annotaded class(es) to initialize the DispatcherServlet context (replaces the old dispatcher-servlet.xml)
This is the web.xml :
public class WebAppConf extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
// declare root context configuration classes
return new Class<?>[]{ RootConf.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
// declare servlet context configuration classes
return new Class<?>[]{ ServletConf.class };
}
#Override
protected String[] getServletMappings() {
// mapping of DispatcherServlet
return new String[]{"/"};
}
#Override
protected void customizeRegistration(Dynamic registration) {
// additional configuration, here for MultipartConfig
super.customizeRegistration(registration);
MultipartConfigElement multipartConf = new MultipartConfigElement("", 200000L, -1L, 0);
registration.setMultipartConfig(multipartConf);
}
}
RootConf will declare business model, service and dao beans and is not shown here.
ServletConf declares the controllers and servlet configuration :
#Configuration
#EnableWebMvc
// declare where to find annotated controllers
#ComponentScan({"org.example.web"})
public class ServletConf extends WebMvcConfigurerAdapter {
#Bean
MultipartResolver multipartResolver() {
return new StandardServletMultipartResolver();
}
#Bean
ViewResolver internalViewResolver() {
// the view resolver bean ...
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
return resolver;
}
}
As said above, it is squeletal, but it comes from a working minimal example so you should be able to start with that and extend it at will. In my example, the above three classes live in a org.example.config package that will never be scanned for autodetecting other configuration classes or annotated beans.
Hope it helps ...
I know this doesn't answer your question fully, but hopefully the links will be useful.
WebApplicationInitializer - A 100% code based approach to configuration
as well as AnnotationConfigWebApplicationContext
Also, if you have the time, reading the relevant sections of Spring's MVC chapter of their documentation is helpful.
I Wish that this link will be helpful for you Spring security with annotation Mkyong
The latest versions of STS integrate the Spring guides from https://spring.io/guides directly, try the "Import Spring Getting Started Content" wizard. There are good guides included for creating a Spring Boot based web service, for example, among many others.

GWT rpc failing - base url not what I expected

I am trying to become familiar with using the GWT api to create web based applications. I have been following some tutorials on GWT and have not yet been able to make an RPC call. Looking at the problem with a broad scope, my goals are to make a server call to run a series of database tests that I know work (ive tested this code).
---EDIT---
I think that the problem here is that the resource is being looked for here:
/MatesWeb/org.matesweb.Main/peopleService
when I think it should be looked for here:
/MatesWeb/peopleService
---END_EDIT---
Here is the info and code I feel is relevant:
-using netbeans
-error that I am getting is "/MatesWeb/org.matesweb.Main/PeopleService - description - The requested resource is not available."
-GWT.getModuleBaseURL() returns: :8080/MatesWeb/org.matesweb.Main/
-URL in browser is: :8080/MatesWeb/
from web.xml file
<servlet>
<servlet-name>peopleService</servlet-name>
<servlet-class>org.matesweb.server.PeopleServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>peopleService</servlet-name>
<url-pattern>/peopleService</url-pattern>
</servlet-mapping>
From PeopleService Service
package org.matesweb.client;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
#RemoteServiceRelativePath("PeopleService")
public interface PeopleService extends RemoteService {
String[] saveGetPerson(String[] persInfo);
int runTests();
}
From PeopleServiceImpl
package org.matesweb.server;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import org.matesweb.client.PeopleService;
import org.matesweb.server.tests.DbTest;
class PeopleServiceImpl extends RemoteServiceServlet implements PeopleService {
#Override
public String[] saveGetPerson(String[] persInfo) {
throw new UnsupportedOperationException("Not supported yet.");
}
#Override
public int runTests()
{
int retInt;
DbTest dbTest = new DbTest();
retInt = dbTest.runTests();
return retInt;
}
}
From PeopleServiceAsync
package org.matesweb.client;
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface PeopleServiceAsync
{
void saveGetPerson(String[] persInfo, AsyncCallback<String[]> persInformation);
void runTests(AsyncCallback<Integer> retInt);
}
Any idea of whats going on here?
Cheers,
Nick
#RemoteServiceRelativePath("PeopleService")
The #RemoteServiceRelativePath annotation is used to decide what url to hit. This path to the server is relative to the compiled module itself - the gwt app loaded from the path /MatesWeb/org.matesweb.Main/, so the service is being sought out at /MatesWeb/org.matesweb.Main/PeopleService. I assume this means you have an html file in the MatesWeb/ directory (probably the .war file is called MatesWeb?), and inside of there exists the compiled app in org.matesweb.Main/, including the initial JS file, org.matesweb.Main.nocache.js.
If you want to tell the service to be found at /MatesWeb/peopleService, you have two options. The first is to modify the annotation to back up a directory, something like this:
#RemoteServiceRelativePath("../peopleService")
Using .., I indicate the parent directory, and I also changed the case of the path part 'peopleService' - this may or may not matter. A second option is to set the url programmatically:
PeopleServiceAsync service = GWT.create(PeopleService.class);
((ServiceDefTarget)service).setServiceEntryPoint("/MatesWeb/peopleService");
As referenced in the #RemoteServiceRelativePath javadocs http://google-web-toolkit.googlecode.com/svn/javadoc/latest/com/google/gwt/user/client/rpc/RemoteServiceRelativePath.html.
If, instead, you want to leave the client as is and tell the server that this service should be at the path the client expects, you can modify the web.xml to make the servlet available at the path that the client is currently expecting to find it:
<servlet-mapping>
<servlet-name>peopleService</servlet-name>
<url-pattern>/MatesWeb/org.matesweb.Main/PeopleService</url-pattern>
</servlet-mapping>
Note again that I've changed the case - it may not matter, but I generally like to be consistent.
First hunch is PeopleService must be peopleService in the #RemoteServiceRelativePath . Please use firebug to monitor your rpc requests. You can observe and verify request url issues like these easily.
Update your URL pattern in web.xml as in here
<url-pattern>/org.matesweb.Main/greet</url-pattern>