Does anyone know how I can get the original header fields from request? I would like to validate, if client will receive html or just plain/text response. Can I get this fields inside 'toResponse' method of exceptionMapper?
I created exceptionMapper like in this post:
http://gary-rowe.com/agilestack/2012/10/23/how-to-implement-a-runtimeexceptionmapper-for-dropwizard/
If you did want to get information from the original request object, you can add the following to your controller.
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.Context;
#Path("/my")
#Produces(["application/json", "application/hal+json"])
class MyController {
#Context
protected HttpServletRequest httpRequest
#Timed
#GET
public Response getOne(){
httpRequest.getHeaders();
... //do something with headers
return Response.ok(new Person(id:1), httpRequest.getContentType());
}
Related
I am running two different Payara Micro microservices in one cluster.
The issue I have is that when I try to access the OpenAPI URL of MyApp1 like http://mylink.com/myApp1/openapi it does not work. It actually works when I use URL http://mylink.com/openapi.
This becomes an issue when I want to see the API for the other microservice like http://mylink.com/myApp2/openapi which does not work.
Is there a way in Payara Micro of telling OpenAPI to use the application's context in it's path just like all the other URL in the application do?
As you can see in my previous comment, I've also struggled with the same situation.
Context - openapi and microprofile
First let me say that having /openapi URL in the root is the intended behaviour of microprofile-open. Documentation always uses /openapi path as the right to get the document LINK
In the implementation, is very clear that this behaviour is both wanted as enforced:
In the ServletContainerInitializer for OpenApi one can see the following code
// Only deploy to app root
if (!"".equals(ctx.getContextPath())) {
return;
}
Workaround aka Solution.
Now that is clear that we cannot configured this, since it's intended behaviour, one solution ( the one I'm proposing ) is to proxy the request to /YOUR_APP/openapi to /openapi.
Since my application is a jax-rs one, deployed on openshift, and I don't want to have a dedicated proxy application for this, I've just created a simple Resource/Controller to proxy this specific request for me.
The outstanding method behind:
#GET
#Path("")
public Response proxyOpenApiCall(){
log.debug("proxyOpenApiCall called");
String entity = client.target("http://localhost:8080")
.path("openapi").request()
.get(String.class);
return Response.ok(entity).build();
}
I was able to fix this with a small forward proxy. Therefore I create a new REST enpoint wich is callable from public and returns the content of internal http endpoint.
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.RequestScoped;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
#RequestScoped
#ApplicationPath("/")
#Path("/")
public class OpenApiProxyRestFacade extends Application {
private Client client;
#PostConstruct
public void init() {
this.client = ClientBuilder.newClient();
}
#GET
#Path("/openapi")
#Produces(MediaType.APPLICATION_JSON)
public Response proxyOpenApiCall() {
String entity = client.target("http://localhost:9080").path("openapi").request().get(String.class);
return Response.ok(entity).build();
}
#GET
#Path("/openapi/ui")
#Produces(MediaType.APPLICATION_JSON)
public Response proxyOpenApiUiCall() {
String entity = client.target("http://localhost:9080/openapi").path("ui").request().get(String.class);
return Response.ok(entity).build();
}
#PreDestroy
public void destroy() {
this.client.close();
}
}
For openapi, you can set this property for change of url, so it is configurable after all
mp.openapi.extensions.path=/yourapi/whatever
and for the openapi-UI set this
openapi.ui.yamlUrl=/yourapi/whatever
Sources: I first googled for mp.openapi.xxx parameters, (I found them in source code) which led me to this url
https://download.eclipse.org/microprofile/microprofile-open-api-1.0/microprofile-openapi-spec.html
and after looking for more stuff there was one simple sentence mentioning that there is also mp.openapi.extensions and after googling those further I found this random doc here https://github.com/wildfly/wildfly/blob/main/docs/src/main/asciidoc/_admin-guide/subsystem-configuration/MicroProfile_OpenAPI.adoc
I'm trying to trasform http GET method call from legacy api server built with MVC1 pattern to new restful api server without any change of front-end source code using netflix zuul and eureka.
I added zuul pre filter transforming legacy url to restful convention url working after PreDecorationFilter and it works fine.
But now I'm facing problem converting the GET method to proper method like POST, PUT, DELETE by distinguising url so that the requests are properly mapped in spring controller via #GetMapping/#PostMapping/#PutMapping/#DeleteMapping.
I looked into SimpleRoutingFilter that handles HttpClient but
Because of environmental constraint, I have to use eureka service id to route to the new api server and that means I should use RibbonRoutingFilter which is quite complicated to find out a right place to this operation in.
So, is this possible to change http method or make new http request before RibbonRoutingFilter?
If possible can you please suggest where is the right place to do that or some reference?
Many thanks!
======================================================================
Milenko Jevremovic,
Would you please tell me more detail about using Feign?
I defiend #FeignClient like below
#PostMapping(value = "{url"}, consumes = "application/json")
ResponseEntity<?> postMethod(#PathVariable("url") String url);
and to get query parameters to request body for POST In zuul pre filter,
after transform logic from GET request url to POST new restful url ...
byte[] bytes = objectMapper.writeValueAsBytes(ctx.get("requestQueryParams"));
ctx.setRequests(new HttpServletRequestWrapper(request) {
#Override ..getMethod
#Override ..getContentLength
#Override ..getConentLengthLong
#Override
public ServletInputStream getInputStream() {
return new ServletInputStreamWrapper(bytes);
}
}
ResponseEntity<?> response feignClient.post(transformedNewApiUri);
and set RequestContext code that you suggested ....
and controller of new api server is like,
#PostMapping
ResponseEntity<model> post(#RequestBody req..)
It comes to controller fine but when I see the http request in post method of controller,
There is no request body for parameters.
(HttpServleterRequest getInputStream shows empty)
The request data set in zuul pre filter by HttpServletRequestWrapper is
not used in Feign maybe...?
Would you please get me more idea setting request body when changing GET query
to POST constructor for using Feign?
It is not possible to change method of HttpServletRequest, but it's possible to replace request in RequestContext. HttpServletRequestWrapper appears to be very helpful:
static class PostHttpServletRequest extends HttpServletRequestWrapper {
public PostHttpServletRequest(HttpServletRequest request) {
super(request);
}
#Override
public String getMethod() {
return "POST";
}
}
So method run can be rewritten as following:
#Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
HttpServletRequest requestWrapper = new PostHttpServletRequest(request);
ctx.setRequest(requestWrapper);
return null;
}
After doing some research did not find any built in solution.
But what comes in my mind you can use Feign client in your Pre filter, get the response, set the response and return it immediately to client from your Pre filter.
You can set Feign client url or your service id, like it is explained in the docs, it uses ribbon as well .
Change response in your run method like:
...
RequestContext ctx = RequestContext.getCurrentContext();
ctx.setResponseStatusCode(your_code);
ctx.setResponseBody(new_body);
ctx.setSendZuulResponse(false);
return null
I want to get a token from the Authorization header of the request.
import 'dart:async';
import 'package:aqueduct/aqueduct.dart';
class SecretController extends ResourceController {
#Operation.get()
Future<Response> signin() async {
request.headers // ??? not available
}
}
How do I access that header in Aqueduct?
A request is a wrapper around a raw HttpRequest object from the Dart standard library, so one way is to access it like this:
request.raw.headers["authorization"]
You can also bind the value of a header to a method parameter; this is nice when you want to parse the string header value into another type and/or validate the header. (You can do some really convenient stuff with binding.)
#Operation.get()
Future<Response> signIn(
#Bind.header("authorization") String authorization) async {
...
}
Finally, specific to the Authorization header, you can use Authorizer middleware. This validates the authorization header and creates an Authorization object with the details of authorized resource owner ('the user') that you can access from your method.
router.route("/secret")
.link(() => Authorizer.bearer(authServer))
.link(() => SecretController());
...
#Operation.get()
Future<Response> signIn() async {
final userIDForRequest = request.authorization.ownerID;
}
I've faced a problem when I get base URI form uriInfo. Here's a part of code:
#Path("/users")
#POST
public Response createUser(#RequestBody User user, #Context UriInfo uriInfo) {
...
String confirmEmailUrl = uriInfo.getBaseUri().resolve("/users/confirm/" + getConfirmEmailLink(user));
...
}
confirmEmailUrl must be like http://XXX.XXX.XXX.XXX:8080/users/confirm/aergserthserg but I get the following result http://XXX.XXX.XXX.XXX/users/confirm/aergserthserg. The problem within the port. I used in some other methods uriInfo to build the URL and it works correctly. What is wrong here?
Grails has a request object which is defined here.
The problem is when I try to use it, I get:
No such property: request for class:xxx
Reading the first 100 hits googling this error only produced one suggestion:
import javax.servlet.http.HttpServletRequest
import org.springframework.web.context.request.ServletRequestAttributes
:
def my() {
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest();
}
However, this gives:
groovy.lang.MissingPropertyException: No such property: RequestContextHolder for class: net.ohds.ReportService
How does one get a handle on the request object in Grails?
How do you find out about this? So few people have asked this question, it must be documented somewhere, or in some example, but I can't find either.
In Grails 3.0, from a service get the request object using:
grails-app/services/com/example/MyService.groovy
import org.grails.web.util.WebUtils
...
def request = WebUtils.retrieveGrailsWebRequest().getCurrentRequest()
def ip = request.getRemoteAddr()
Documentation:
https://docs.grails.org/latest/api/org/grails/web/util/WebUtils.html#retrieveGrailsWebRequest()
Note:
The old codehaus package has been deprecated.
Try following code:
import org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequest
import org.codehaus.groovy.grails.web.util.WebUtils
...
GrailsWebRequest webUtils = WebUtils.retrieveGrailsWebRequest()
def request = webUtils.getCurrentRequest()
I expect that you probably got "groovy.lang.MissingPropertyException: No such property: RequestContextHolder for class: net.ohds.ReportService" because you didn't import the "org.springframework.web.context.request.RequestContextHolder" class in your ReportService.
The most common place to want access to the request object is in a controller. From a controller you simply refer to the request property and it will be there. See http://grails.org/doc/latest/ref/Controllers/request.html.
The answer to how to access the request object from somewhere else may depend on what the somewhere else is.
UPDATE
I don't know why you are having trouble passing the request from a controller to a service, but you can. I suspect you are invoking the method incorrectly, but something like this will work...
// grails-app/services/com/demo/HelperService.groovy
package com.demo
class HelperService {
// you don't have to statically type the
// argument here... but you can
def doSomethingWithRequest(javax.servlet.http.HttpServletRequest req) {
// do whatever you want to do with req here...
}
}
A controller...
// grails-app/controllers/com/demo/DemoController.groovy
package com.demo
class DemoController {
def helperService
def index() {
helperService.doSomethingWithRequest request
render 'Success'
}
}