Quarkus - How to implement routing for Single Page Apps? - quarkus

How to implement routing in Quarkus if used with frontend frameworks like React, VueJS, Angular, etc?
For example, for any url "/xyz" the order of route evaluation should be:
Static file named "xyz", if exists.
Controller annotated with #Path("/xyz"), if exists.
404 -> serve "/index.html"

Quarkus already does 1 and 2 for you.
For 3, you only need to implement a custom NotFoundExceptionMapper
#Provider
public class NotFoundExceptionMapper implements ExceptionMapper<NotFoundException> {
#Override
#Produces(MediaType.TEXT_HTML)
public Response toResponse(NotFoundException exception) {
InputStream resource = ClassLoader.getSystemResourceAsStream("META-INF/resources/index.html");
return null == resource
? Response.status(NOT_FOUND).build()
: Response.ok().entity(resource).build();
}
}
Quarkus will use by order:
File xyz, if exists in src/main/resources/META-INF/resources/
Resource #Path("/xyz")
Custom NotFoundExceptionMapper

Related

How to have dynamic base URL with Quarkus MicroProfile Rest Client?

Quarkus using Rest Client, explains how to use the MicroProfile REST Client. For Base URL application.properties can be used.
org.acme.restclient.CountriesService/mp-rest/url=https://restcountries.eu/rest #
With above approach, cant have dynamic base URL.
Able to achieve it by using RestClientBuilder as explained in MicroProfile Rest Client. Downside of this approach is not having auto-negotiation capability.
SimpleGetApi simpleGetApi = RestClientBuilder.newBuilder().baseUri(getApplicationUri()).build(SimpleGetApi.class);
Is there other or better way to achieve this? Thanks.
While it is true, that the MP Rest CLient does not allow you to set the BaseUri dynamically when you use declarative/Injected clients, there are some (albeit hacky) ways how to achieve that.
One is to use standard ClientRequestFilter which can modify the URL:
#Provider
#Slf4j
public class Filter implements ClientRequestFilter {
#Inject RequestScopeHelper helper;
#Override
public void filter(ClientRequestContext requestContext) throws IOException {
if (helper.getUrl() != null) {
URI newUri = URI.create(requestContext.getUri().toString().replace("https://originalhost.com", helper.getUrl()));
requestContext.setUri(newUri);
}
}
}
Where RequestScopeHelper is some help class (e.g. request scoped bean) through which you can pass the dynamic url, for example:
#Inject
RequestScopeHelper helper;
#Inject
#RestClient
TestIface myApiClient;
public void callSomeAPIWithDynamicBaseUri(String dynamic) {
helper.setUrl(dynamic);
myApiClient.someMethod();
}
Second is to use MP rest client SPI, namely the RestClientListener which allows you to modify the rest clients after they are built.
For this to work, you have to set the scope of your rest client to RequestScoped so that new instance is created for each request(if you use singleton for example, then the client is only created once and your listener will only be called once). This you can do via quarkus properties:
quarkus.rest-client."com.example.MyRestIface".scope=javax.enterprise.context.RequestScoped
public class MyListener implements RestClientListener {
#Override
public void onNewClient(Class<?> serviceInterface, RestClientBuilder builder) {
String newUri = //obtain dynamic URI from somewhere e.g. again request scope bean lookup, or maybe dynamic config source (create new in-memory ConfigSource, before you invoke your rest client set the corresponding rest client url property to your dynamic value, then inside this listener use ConfigProvider.getConfig().getProperty...)
builder.baseUri(URI.create(newUri));
}
}
Don't forget to register this listener as service provider(META-INF/services/org.eclipse.microprofile.rest.client.spi.RestClientListener)
Another option is to use custom CDI producer that would produce the Rest client instances for you; then you could control all client config yourself. You can use the RestClientBase from Quarkus rest client which is exactly what Quarkus uses under the hood during deployment phase to construct client instances. You will however have to duplicate all the logic related to registration of handlers, interceptors etc.
Do keep in mind, that any of these solutions will make the debugging and problem analysis more challenging - because you will now have multiple places, where the URI is controlled(MP config/quarkus properties, env vars, your custom impl...), so you need to be careful with your approach and maybe add some explicit log messages when you override the URI manually.
MicroProfile REST Client in Quarkus does allow you to use dynamic base URL with that simple "hack" :
Just put an empty String in #Path annotations for you API interface like that :
import javax.ws.rs.GET;
import javax.ws.rs.Path;
#Path("")
public interface SimpleGetApi {
#Path("")
#GET
String callWithDynmamicUrl(); //it can be String or any return type you want
}
After that you are ready to call your dynamic base URL :
import org.eclipse.microprofile.rest.client.RestClientBuilder;
import java.net.URI;
public class Example {
public static void main(String[] args) {
URI anyDynamicUrl = URI.create("http://restcountries.eu/rest/some/dynamic/path");
SimpleGetApi simpleGetApi = RestClientBuilder.newBuilder().baseUri(anyDynamicUrl)
.build(SimpleGetApi.class);
simpleGetApi.callWithDynmamicUrl();
}
}

how to Enforce request header on all spring web RestController equests

Is there an option to specify a request header once in spring web RestController instead of doing it on every request?
e.q.
#RestController("workflowController")
public class MyClass{
public Value list(#RequestHeader(USER_ID_HEADER_PARAM) String user) {
...some code
}
public Workflow create(#RequestBody Workflow workflow, #RequestHeader(USER_ID_HEADER_PARAM) String user) {
... some code
}
}
the #RequestHeader(USER_ID_HEADER_PARAM) will be repeated in every request.
is there a way to specity it in the #RestCotroller level or the class level?
Thanks
Use some kind of filter class that can be configured to wrap around your requests in your servlets based on the URL path.
Here is info about the generic Servlet API filter API:
https://www.oracle.com/technetwork/java/filters-137243.html
If you're using Spring, there's another way to do it:
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#filters
https://www.baeldung.com/intercepting-filter-pattern-in-java

How do I add API Endpoints in ASP.NET?

I would like to register API Endpoints in ASP.NET by just adding few methods in ApiController. A new method there means a new API.
In a random example below:
public class ProductController : ApiController
needs to serve the following Endpoints:
/
/price
/price/discount
Problem here is all endpoints are having a GET request to /, and result in same output as /.
Reference URL and Service Contract
You can place Route annotation at method for which you want to use custom route.
public class CustomersController : ApiController
{
// this will be called on GET /Customers or api/Customers can't remember what default
//config is
public List<Customer> GetCustomers()
{
...
}
// this will be called on GET /My/Route/Customers
[HttpGet, Route("My/Route/Customers)]
public List<Customer> GetCustomersFromMyRoute()
{
...
}
}

Jaxb setting dynamic #XmlRootElement with Spring Web Services

I have a Spring application that consumes a SOAP web services. I have several classes that are quite simple and only differ in the #XmlRootElement. I'm wondering if there's a way to create a more generic class that I can set the root element on dymanically.
Here's a few of the classes with only the root element being different.
#XmlRootElement(name="safetydate")
public class SafetyDateRequest extends Carrier411RequestImpl {
}
#XmlRootElement(name="checkallsafety")
public class SafetyGetAllRequest extends Carrier411RequestImpl {
}
#XmlRootElement(name="checksafetyupdates")
public class SafetyGetUpdatesRequest extends Carrier411RequestImpl {
}
In another class, I'm processing these classes in the following fashion:
private void sendRequest(Carrier411Request request, Carrier411ResponseHandler responseHandler) throws FaultCodeException {
Carrier411Response response = (Carrier411Response) ws.marshalSendAndReceive(registry.get(request.getClass()), request);
checkResponseForFault(response);
responseHandler.handleResponse(request, response);
}
I know there's another version of marshalSendAndReceive that accepts a callback allowing you to modify the request before actually sending it, but I haven't figured out how to achieve what I'm trying to do.

Spring MVC : how to get the mapped URI within a method marked with #RequestMapping

I'm currently working on a Spring MVC application and as I mapped, within the web.xml file, all incoming URL to a single DispatcherServlet, I wanted to know whether it would be possible to retrieve the URI that has been effectively mapped. Here's an example to illustrate my concerns :
import static org.springframework.web.bind.annotation.RequestMethod.*;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
public class HomeController {
#RequestMapping(method={GET})
public String processAllRequest(){
return "viewName";
}
}
Since I've defined the URL-MAPPING in the web.xml as being "/*", all incoming requests will end up in my controller class, show above. For instance, both the following requests will be processed by the processAllRequest() method from my controller.
myApplicationContext/home
myApplicationContext/logout
Is it possible, somehow, to retrieve the mapped URI? That is, once I'm inside the processAllRequest(), how could I know if it's been called for .../home or .../logout?
Is it possible to retrieve this kind of info by injecting an HttpServletRequest or another object as argument of the method?
Spring does inject HttpServletRequest if you put it in your handler arguments, so you can do that if you like.
But if you need to distinguish between different URLs, just place them in different handlers:
#Controller
public class HomeController {
#RequestMapping(value="/home", method={GET})
public String processHome(){
return "viewName";
}
#RequestMapping(value="/login", method={GET})
public String processLogin(){
return "viewName";
}
}
The mapping in web.xml forwards all requests to the spring servlet. You can still write as many #Controllers as you like, and play with class-level and method-level #RequestMapping to split the application into logical components.
I might have formulated my question in an ambiguous way but what I was looking for, was rather path variable. So my problem was solved this way :
#Controller
public class HomeController {
#RequestMapping(value="/{uri}", method={GET})
public String processMappedUri(#PathVariable uri){
return uri;
}
}
With this solution whenever I request the following requests, the uri argument from my processMappedUri() method will hold the variable value :
myApplicationContext/home --> uri = home
myApplicationContext/logout --> uri = logout

Resources