Reputation:
Currently, I'm using Tomcat to keep my Backend along with my Rest API. When I want to use my Frontend, I'm just starting Tomcat, which holds the Backend-Project and then, I can access the the backend over the Rest-API using http-requests. Now I thought about getting rid of Tomcat and deploy it as a jar file, instead of a war file and run it locally via a Main method. I've done it like that (Source):
public class Main {
public static void main(String[] args) throws Exception {
ResourceConfig config = new DefaultResourceConfig(RestApi.class);
HttpServer server = HttpServerFactory.create("http://localhost:8080/", config);
server.start();
}
An excerpt of my Rest-Class would be:
@Path("/schemas")
public class RestApi {
@GET
@Path("/hi")
public String dropHi() {
return "hi;
}
}
Running this main works, but for some reason still can't access the Rest-Api. When I'm trying to get a "hi" by trying to reach http://localhost:8080/api/schemas/hi
in the browser nothing happens. What could be wrong, does it even make sence what I'm trying to do?
The idea is to run the backend later on a server without using Tomcat, just running it as a jar file and access it via the frontend, which you run locally on your system.
Upvotes: 0
Views: 1458
Reputation:
I did it. There were two problems:
In my web.xml there was <url-pattern>/api/*</url-pattern>
, which wasn't used anymore so the link isn't http://localhost:8080/api/schemas/hi
, but http://localhost:8080/schemas/hi
.
In my web.xml I got the entry:
<filter>
<filter-name>CORS</filter-name>
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
<init-param>
<param-name>cors.supportedMethods</param-name>
<param-value>GET, POST, HEAD, PUT, DELETE</param-value>
</init-param>
</filter>
Not using a container anymore, I had to enable CORS another way. Finally I did it with the help of this like that:
public class CORSFilter implements ContainerResponseFilter {
public ContainerResponse filter(ContainerRequest req, ContainerResponse containerResponse) {
ResponseBuilder responseBuilder = Response.fromResponse(containerResponse.getResponse());
// *(allow from all servers) OR http://example.com/
responseBuilder.header("Access-Control-Allow-Origin", "*")
// As a part of the response to a request, which HTTP methods can be used during the actual request.
.header("Access-Control-Allow-Methods", "API, CRUNCHIFYGET, GET, POST, PUT, UPDATE, OPTIONS")
// How long the results of a request can be cached in a result cache.
.header("Access-Control-Max-Age", "151200")
// As part of the response to a request, which HTTP headers can be used during the actual request.
.header("Access-Control-Allow-Headers", "x-requested-with,Content-Type");
String requestHeader = req.getHeaderValue("Access-Control-Request-Headers");
if (null != requestHeader && !requestHeader.equals(null)) {
responseBuilder.header("Access-Control-Allow-Headers", requestHeader);
}
containerResponse.setResponse(responseBuilder.build());
return containerResponse;
}
}
And set it in the Main method:
config.getContainerResponseFilters().add(CORSFilter.class);
Upvotes: 1
Reputation: 9795
What you are trying to do makes sense. You want a standalone server and there is nothing wrong with that.
I did similar things, but with Jetty server and RESTEasy implementation of REST. Although I am not sure that everything will work out of the box for you (most probably not) it should still be very similar as both Jersey REST and RESTEasy are built according to the same specs: https://jcp.org/en/jsr/detail?id=311
Anyways, here is what works for me:
//Obviously main method from which you start the server
public static void main(String[] consoleArgs) {
final Server server= new Server(port);
final HandlerList handlers= new HandlerList();
addServlets(handlers);
server.setHandler(handlers);
server.start();
}
private static void addServlets(HandlerList handlers) {
final ServletContextHandler servletContextHandler= new ServletContextHandler(ServletContextHandler.SESSIONS);
servletContextHandler.setContextPath("/");
handlers.addHandler(servletContextHandler);
//handlers and servlets that I ommit...
addRestServiceContainer(servletContextHandler);
}
// and here is the trick...
// the settings you see here would normally go to web.xml file
private static void addRestServiceContainer(final ServletContextHandler servletContextHandler) {
ServletHolder holder= new ServletHolder(new HttpServlet30Dispatcher());
holder.setInitParameter("javax.ws.rs.Application", "com.stackoverflow.rest.application.RestfulServiceContainer");
holder.setInitParameter("resteasy.servlet.mapping.prefix", "/rest");
holder.setInitParameter("resteasy.providers", "org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider");
servletContextHandler.addServlet(holder, RestResourcePaths.REST_SERVICES_BASE_PATH + "/*");
}
And as a final piece, here is how com.stackoverflow.rest.application.RestfulServiceContainer
looks:
public class RestfulServiceContainer extends Application {
private static final Set<Class<?>> fSingletons= new HashSet<Class<?>>();
private static final Set<Object> fRestfulServices= new HashSet<Object>();
public RestfulServiceContainer() {
registerServices();
initProviders();
}
/**
* Normally, when resteasy.scan is set to true all provider classes (with @Provider) are registered automatically,
* but since this is a standalone Jetty app it doesn't work. So, we register provider classes here manually.
*/
private void initProviders() {
fSingletons.add(TrafficInterceptor.class);
fSingletons.add(LogInterceptor.class);
fSingletons.add(RateLimitInterceptor.class);
fSingletons.add(SecurityInterceptor.class);
fSingletons.add(ExceptionHandler.class);
}
private void registerServices() {
fRestfulServices.add(new GetWhateverService());
fRestfulServices.add(new PostStuffService());
}
@Override
public Set<Class<?>> getClasses() {
return fSingletons;
}
@Override
public Set<Object> getSingletons() {
return fRestfulServices;
}
}
Upvotes: 1