REST Call with list of headers - java

I have the following code snippet for invoking rest call. I have around 8 headers to pass on for this rest call. But the problem is that it is difficult to manage. If in case the list of headers are increased in future, I need to change evaluateChange method signature to include the additional headers as method params.
#Path("/v1/restclienturi/")
#Consumes({ MediaType.APPLICATION_JSON })
#Produces({ MediaType.APPLICATION_JSON })
public interface RestClient {
#POST
#Path("/samplecall/evaluate")
Response evaluateChange(
#HeaderParam("HEADER1") String header1,
#HeaderParam("HEADER2") String header2,
#HeaderParam("HEADER3") String header3,
#HeaderParam("HEADER4") String header4,
#HeaderParam("HEADER5") String header5,
#HeaderParam("HEADER6") String header6,
#HeaderParam("HEADER7") String header7,
#HeaderParam("HEADER8") String header8,
#Context HttpServletResponse response, Request request);
}
Please provide your thoughts or code snippet to accommodate this.
I tried the following code snippet but it did not work(where headerMap contains all the 8 headers in it):
#Path("/v1/restclienturi/")
#Consumes({ MediaType.APPLICATION_JSON })
#Produces({ MediaType.APPLICATION_JSON })
public interface RestClient {
#POST
#Path("/samplecall/evaluate")
Response evaluateChange(
#RequestHeader Map<String, String> headerMap,
#Context HttpServletResponse response, Request request);
}

I found a solution using javax.ws.rs.core.Form:
#Path("/v1/restclienturi/")
#Consumes({ MediaType.APPLICATION_JSON })
#Produces({ MediaType.APPLICATION_JSON })
public interface RestClient {
#POST
#Path("/samplecall/evaluate")
Response evaluateChange(
#Form MyHeader headers,
#Context HttpServletResponse response, Request request);
}
The following is the MyHeader which is a pojo:
public class MyHeader{
#HeaderParam("HEADER1")
private String header1;
#HeaderParam("HEADER2")
private String header2;
.....
// getters and setters present
}
Instantiate MyHeader and set the values to pass it on to the REST service like:
MyHeader headers = new MyHeader();
headers.setHeader1("HEADER1_VALUE");
...
and call: evaluateChange(headers, null,request);
PROBLEM:
The very big problem with this approach is that everytime there is a new header added we need to make a code change to set and get the values. If the solution is something like passing as a colletion then we don't have that code change involved when new headers are added. like:
Map<String,String> headersMap = new HashMap();
headers.put("HEADER1","HEADER1_VALUE");
....
evaluateChange(headersMap,null,request);
I am looking for a solution like this. But the above code did not work. Looking for suggestions.

Not exactly sure what you mean, but if you want to get all headers how about this:
public Response evaluateChange(#Context HttpHeaders headers, ...) {
String header1 = headers.getRequestHeader("HEADER1").get(0);
...
}
Found some more code about this here: http://www.mkyong.com/webservices/jax-rs/get-http-header-in-jax-rs/
Edit: How to call the method with a map of key-values.
public class MapHttpHeaders implements HttpHeaders {
private Map<String, String> values;
public MapHttpHeaders(Map<String, String> values) {
this.values = values;
}
#Override
public String getHeaderString(String key) {
return values.get(key);
}
#Override
public List<String> getRequestHeader(String key) {
String value = getHeaderString(key);
if (value == null) {
return null;
} else {
return asList(value);
}
}
...and so on...
}
And then just do:
evaluateChange(new MapHttpHeaders(values), ...);

Couldn't you just inject HttpServletRequest and then use its getHeader(String name) method?
API
#POST
#Path("/samplecall/evaluate")
Response evaluateChange(
#RequestHeader Map<String, String> headerMap,
#Context HttpServletResponse response,
#Context HttpServletRequest httpRequest,
Request request);
Impl
#Override
public Response evaluateChange(
#RequestHeader Map<String, String> headerMap,
#Context HttpServletResponse response,
#Context HttpServletRequest httpRequest,
Request request) {
String header1 = httpRequest.getHeader("HEADER1");
...
Of course, that way you are hiding part of your contract in the implementation.

You can send all headers set in a MultivaluedHashMap (javax.ws.rs.core.MultivaluedHashMap) to the Form. this is an acceptable constructor argument for the Form.
MultivaluedMap<String, String> headerMap = new MultivaluedHashMap<String, String>();
headersMap.putSingle("HEADER1","HEADER1_VALUE");
headersMap.putSingle("HEADER2","HEADER1_VALUE");
.
.
.
headersMap.putSingle("HEADER8","HEADER8_VALUE");
evaluateChange(headersMap,null,request);
and change your evaluateChange as below,
Response evaluateChange(
#Form MultivaluedMap headers,
#Context HttpServletResponse response, Request request);
Hope this helps.. Good luck !!

Not sure why you are trying a Map and not simply a List:
#Path("/v1/restclienturi/")
#Consumes({ MediaType.APPLICATION_JSON })
#Produces({ MediaType.APPLICATION_JSON })
public interface RestClient {
#POST
#Path("/samplecall/evaluate")
Response evaluateChange(
#HeaderParam("HEADER") List<String> headers,
#Context HttpServletResponse response, Request request
);
}
Now I did not test this, but this would require all HeaderParams to be called 'HEADER', and they will/should be stored in the List<String> following the order of occurrence.

Related

How to implement squer brackets parameter with Jax-RS client? [duplicate]

I am building a generic web service and need to grab all the query parameters into one string for later parsing. How can I do this?
You can access a single param via #QueryParam("name") or all of the params via the context:
#POST
public Response postSomething(#QueryParam("name") String name, #Context UriInfo uriInfo, String content) {
MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
String nameParam = queryParams.getFirst("name");
}
The key is the #Context jax-rs annotation, which can be used to access:
UriInfo, Request, HttpHeaders,
SecurityContext, Providers
The unparsed query part of the request URI can be obtained from the UriInfo object:
#GET
public Representation get(#Context UriInfo uriInfo) {
String query = uriInfo.getRequestUri().getQuery();
...
}
Adding a bit more to the accepted answer. It is also possible to get all the query parameters in the following way without adding an additional parameter to the method which maybe useful when maintaining swagger documentation.
#Context
private UriInfo uriInfo;
#POST
public Response postSomething(#QueryParam("name") String name) {
MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
String nameParam = queryParams.getFirst("name");
}
ref

Forward a request with the exact same json body

I have a SpringBoot application which simply acts as a middleman. It receives an API request in JSON and forwards this to another server S by calling S's API with the exact same body.
I was exploring the solutions and came across a solution which involved the usage of RestTemplate and MultiValueMap. However, since the json body contains objects rather than simple String, I believe I have to create a DTO with corresponding POJO for the solution to work.
May I ask is the above the only solution, or there is a simple way to forward the request over and get back the response?
Even complex and nested JSON objects can be taken into a Map with key as String and value as Object.
I believe you should just use such a map as your request body and transfer the same to another api.
The middleman server can expose a endpoint that accepts a #RequestBody of Object and
HttpServletRequest then use RestTemplate to forward it to the remote server.
The middleman
#RestController
#RequestMapping("/middleman")
public class MiddleManRestController {
private RestTemplate restTemplate;
#PostConstruct
public void init() {
this.restTemplate = new RestTemplate();
this.restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(this.restTemplate.getRequestFactory()));
}
#RequestMapping(value = "/forward", method = RequestMethod.POST)
public ResponseEntity<Object> forward(#RequestBody Object object, HttpServletRequest request) throws RestClientException {
//setup the url and path
final UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("Remote server URL").path("EnpointPath");
//add query params from previous request
addQueryParams(request, builder);
//specify the method
final RequestEntity.BodyBuilder requestBuilder = RequestEntity.method(HttpMethod.POST, builder.build().toUri());
//add headers from previous request
addHeaders(request, requestBuilder);
RequestEntity<Object> requestEntity = requestBuilder.body(object);
ParameterizedTypeReference<Object> returnType = new ParameterizedTypeReference<Object>() {};
//forward to the remote server
return this.restTemplate.exchange(requestEntity, returnType);
}
private void addHeaders(HttpServletRequest request, RequestEntity.BodyBuilder requestBuilder) {
Enumeration<String> headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
String headerValue = request.getHeader(headerName);
requestBuilder.header(headerName, headerValue);
}
}
private void addQueryParams(HttpServletRequest request, UriComponentsBuilder builder) {
final MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<String, String>();
Map<String, String[]> parameterMap = request.getParameterMap();
if (parameterMap != null) {
parameterMap.forEach((key, value) -> queryParams.addAll(key, Arrays.asList(value)));
}
builder.queryParams(queryParams);
}
}

JAX-RS #Context HttpHeaders always null

I have a Spring Boot application using jax-rs with resteasy (3.0.24). I'm trying to get the HttpHeaders for a request as such:
#DELETE
#Path("/myendpoint")
public Response myMethod(#Context HttpHeaders headers, #Context HttpServletRequest request) {
// headers is always null
}
The headers param is always null even though I'm making the request with multiple headers. As an alternative, I'm extracting them via the HttpServletRequest.getHeaderNames(), but I'd really like know why headers is not populated.
Found the (embarrassing, although I deflect the blame to the author:)) error. #Context HttpHeaders headers was using Spring's implementation and not that from jax-rs.
You gotta get the headers using the #Context then check if the one one you want is there.
#Path("/users")
public class UserService {
#GET
#Path("/get")
public Response addUser(#Context HttpHeaders headers) {
String userAgent = headers.getRequestHeader("user-agent").get(0);
return Response.status(200)
.entity("addUser is called, userAgent : " + userAgent)
.build();
}
}

jersey. why doesn't parameter pass?

I have following jersey method:
#POST
#Path("path")
#Produces({MediaType.APPLICATION_JSON})
public Response isSellableOnline(#QueryParam("productCodes") final List<String> productCodes,
#QueryParam("storeName") final String storeName,
#Context HttpServletRequest request) {
System.out.println(storeName);
System.out.println(productCodes.size());
...
}
in rest client I sends following data:
in console I see
null
0
What do I wrong?
You're reading the parameters from query string, which go in the form:
http://yourserver/your/service?param1=foo&param2=bar
^ start of query string
But you're sending the parameters as part of the form.
Change the way you consume the parameters in your service:
#POST
#Path("path")
#Produces({MediaType.APPLICATION_JSON})
public Response isSellableOnline(#FormParam("productCodes") final List<String> productCodes,
#FormParam("storeName") final String storeName,
#Context HttpServletRequest request) {
System.out.println(storeName);
System.out.println(productCodes.size());
...
}

How can I grab all query parameters in Jersey JaxRS?

I am building a generic web service and need to grab all the query parameters into one string for later parsing. How can I do this?
You can access a single param via #QueryParam("name") or all of the params via the context:
#POST
public Response postSomething(#QueryParam("name") String name, #Context UriInfo uriInfo, String content) {
MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
String nameParam = queryParams.getFirst("name");
}
The key is the #Context jax-rs annotation, which can be used to access:
UriInfo, Request, HttpHeaders,
SecurityContext, Providers
The unparsed query part of the request URI can be obtained from the UriInfo object:
#GET
public Representation get(#Context UriInfo uriInfo) {
String query = uriInfo.getRequestUri().getQuery();
...
}
Adding a bit more to the accepted answer. It is also possible to get all the query parameters in the following way without adding an additional parameter to the method which maybe useful when maintaining swagger documentation.
#Context
private UriInfo uriInfo;
#POST
public Response postSomething(#QueryParam("name") String name) {
MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
String nameParam = queryParams.getFirst("name");
}
ref

Categories