Pass request parameter to delete request in rest - java

I am using resteasy. Here is a code to delete a resource.
#DELETE
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
#Path("/{id:\\d+}")
public Response removeResource(#PathParam("id") int id){
.........................
.. code to delete resource and return Response object ..
.........................
}
This code is working fine. But when I try to pass some parameter to delete request. I am getting UnsupportedMediaException
#DELETE
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
#Path("/{id:\\d+}")
public Response removeResource(#PathParam("id") int id, Map<String, Object> source){
.........................
.. code to delete resource and return Response object ..
.........................
}
I need to send some parameter for some reason. Moreover when I just replace delete request with put request i.e. replacing #DELETE with #PUT, the code works fine.
Is there any way to pass parameter to delete request.
And at front end I was using angularjs's $resource to send DELETE request
var r = $Resource(/rest/resources/1); // for debugging purpose I made id 1
r.remove({"key1":"data1", "key2", "data2"});
Edit :
Stack trace from server
11:43:25,767 ERROR [org.jboss.resteasy.resteasy_jaxrs.i18n] (default task-7) RESTEASY002010: Failed to execute: javax.ws.rs.NotSupportedException: RESTEASY003065: Cannot consume content type
at org.jboss.resteasy.core.registry.SegmentNode.match(SegmentNode.java:382)
at org.jboss.resteasy.core.registry.SegmentNode.match(SegmentNode.java:116)
at org.jboss.resteasy.core.registry.RootNode.match(RootNode.java:43)
at org.jboss.resteasy.core.registry.RootClassNode.match(RootClassNode.java:48)
at org.jboss.resteasy.core.ResourceMethodRegistry.getResourceInvoker(ResourceMethodRegistry.java:445)
at org.jboss.resteasy.core.SynchronousDispatcher.getInvoker(SynchronousDispatcher.java:257)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:194)
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:221)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51)
Response at front-end
Status Code: 415 Unsupported Media Type
Connection: keep-alive
Content-Length: 0
Date: Wed, 01 Jun 2016 06:13:25 GMT
Server: WildFly/10
x-powered-by: Undertow/1

You have requested that the Content-Type be "application/json"
AngularJS defaults to text/plain.
If you have a new enough version of AngularJS(1.1.3) you can customise the resource object to include the Content-Type you requested.
You should be able to modify your resource definition to include the Content-Type for a delete request
var r = $Resource(/rest/resources/1, {},
remove:{
method:"DELETE",
isArray:false,
headers:{'Content-Type':'application/json; charset=UTF-8'}
}
);
For more info see Answer One and Angular issue

Related

Spring Boot: How to resolve Content-Type when incorrectly received from server

I have the following class in Java. I'm expecting it to issue a GET request to the url, get back a JSON payload, and transform that payload to List<LocationData>.
package ...
import ...
#Repository
public class ProxiedLocationRepo {
public List<LocationData> findAll() throws Exception {
RestTemplate restTemplate = new RestTemplate();
String url = UriComponentsBuilder
.fromUriString("https://my-host/path")
.queryParams("some", "queryParams")
.toUriString();
ResponseEntity<List<LocationData>> res = restTemplate.exchange(
url,
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<LocationData>>(){});
if (res.getStatusCode() == HttpStatus.ACCEPTED) {
return res.getBody();
} else {
throw new ResponseStatusException(res.getStatusCode(), "Did not receive a 200 response from Server.");
}
}
}
However, I'm getting back this error:
org.springframework.http.InvalidMediaTypeException: Invalid mime type "charset=UTF-8": does not contain '/'
Which is expected, because if I do the same request from curl, and check the headers I get this (notice Content-Type line):
$ curl -sfi 'https://my-host/path?some=queryParams'
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 06 Mar 2019 13:58:58 GMT
Content-Type: charset=UTF-8
Content-Length: 1821
Connection: keep-alive
Vary: Accept-Encoding
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Frame-Options: SAMEORIGIN
... # perfectly formatted JSON payload here
I know that the Content-Type returned from this server is going to be application/json, but it is not providing it to me.
Is there anyway to inform RestTemplate#exchange of what the Content-Type of the response will be? If not, is there any other methodology I could use to resolve this issue besides getting the owners of the server to set the Content-Type correctly?
EDIT:
I have also tried adding the "Accept" header but got the same results:
$ curl -sfi 'https://my-host/path?some=queryParams' \
-H 'Accept: application/json'
Unfortunately I don't think there's any way to fix this while leveraging the Spring framework. Even if you were to create a custom JsonbHttpMessageConverter that accepts a MIME type of ANY, Spring would still fail to parse the incorrect Content-Type received from the request (because it can't find "/" in the Content-Type string).
So the resolution here was to do use java.net.HttpURLConnection to do the networking instead, and then use com.fasterxml.jackson.databind.ObjectMapper to map from the JSON to a POJO.
It works, but at the cost of no longer being able to leverage any of Spring's HTTP handling, which is likely much much more robust than anything I can implement alone.

Unable to process multipart/report data in Spring 5.0.1. It is only detecting multipart/form-data in the request

I am using Spring 5.0.1 and servlet 3.1.0
When user sends multipart/form-data in the request, spring is able to parse the request and make the parts out of it.
request.getParts() will have those provided multiparts.
But when user sends multipart/report (content-type), spring does not parse this request properly.
It does not give any exception but it does not store anything in the request parts.
request.getParts() will return empty array.
Is there any configuration that has to be done so that spring parses any kind of multipart data.
Posting my code and request payload below:
REST API does not have any restriction on the content type. It takes only request and response as parameters as shown below:
#RequestMapping (value = "/rest/external/integration/{serviceName}", method = RequestMethod.POST)
public void executeAssemblyExternal (HttpServletRequest request,
HttpServletResponse response, #PathVariable String serviceName) throws Exception
{
Parts[] requestParts = request.getParts();
}
Content-type header which is being sent with the request is :
Content-Type multipart/report; Report-Type=disposition-notification; boundary="----=_Part_82_645653877.1526452736757"
Multipart data which is being sent to the REST API is as below:
------=_Part_82_645653877.1526452736757
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
MDN for -
Message ID: <1088014046.24.1526452734879#MCBKUM03.eur.ad.sag>
From: SenderAS2
To: ReceiverAS2
Received on: 2018-05-16 at 12:08:56 (IST)
Status: processed
Comment: This is not a guarantee that the message has been completely processed or understood by the receiving translator
------=_Part_82_645653877.1526452736757
Content-Type: message/disposition-notification
Content-Transfer-Encoding: 7bit
Reporting-UA: webMethods Integration Server
Original-Recipient: rfc822; ReceiverAS2
Final-Recipient: rfc822; ReceiverAS2
Original-Message-ID: <1088014046.24.1526452734879#MCBKUM03.eur.ad.sag>
Received-content-MIC: SezQZhP0aSchqB1zCO0Dq4J0u3U=, sha1
Disposition: automatic-action/MDN-sent-automatically; processed
------=_Part_82_645653877.1526452736757--
As Deinum mentioned in a comment, servlet can not handle multipart requests other than multipart/form-data.
So Written a custom dispatcherServlet where requests having header Content-Type as multipart with subtype other than form-data will be bypassed from getting processed through MultipartResolver.
By doing this request.getInputStream() will have whole multipart data as sent by the user. Necessary actions can be performed on this inputstream at the server side.

Bad header in CXF

I'm working with CXF WebClient, i tried to do a webclient service and make the call with it, i set JSON type in header, but i getting the wild card in the header
I did this for make the webClient
client = WebClient.create(endPoint,Collections.singletonList(new JacksonJsonProvider())).
accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON);
ClientConfiguration config = WebClient.getConfig(client);
config.getInInterceptors().add(new LoggingInInterceptor());
config.getOutInterceptors().add(new LoggingOutInterceptor());
And i have this to make the get call
Response reponse=clientThreadSafe().path("tokens/{id}",virtualToken.getId()).get();
return genericReponse(Token.class,Status.OK,reponse);
With clientThreadSafe
private WebClient clientThreadSafe() throws CertEuropeException{
//thread safe, see http://cxf.apache.org/docs/jax-rs-client-api.html#JAX-RSClientAPI-ThreadSafety
return WebClient.fromClient(client);
}
And genericReponse
private <T> T genericReponse(Class<T> classReponse, Status status, Response reponse ) throws Exception{
if(reponse.getStatusInfo()!=status){
throw new Exception("somthing bad here");
}
return reponse.readEntity(classReponse);
}
But i getting the wildcard in the call
INFOS: Setting the server's publish address to be
http://localhost:9090 mars 14, 2016 1:52:31 PM
org.apache.cxf.interceptor.LoggingOutInterceptor INFOS: Outbound
Message
--------------------------- ID: 1 Address: http://localhost:9090/api/v1/tokens/1 Http-Method: GET
Content-Type: Headers: {Accept=[*/*]}
And i getting one exception
GRAVE: No message body reader has been found for class com.client.Token, ContentType: application/octet-stream
mars 14, 2016 1:52:31 PM
org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper toResponse
AVERTISSEMENT: javax.ws.rs.WebApplicationException: HTTP 415 Unsupported Media Type
I don't know why the WebClient is not taking the MediaType.APPLICATION_JSON header, maybe i don't use the right function for set the headers.
If i try with other rest client, like post man, and i set the right header all seem work fine.
After a lots of test, i found that the "Fluent interface" is not really working like it should, it seem that the order is important, and if you set the accept and the type of the WebClient at the beginning, this can be reset.
So for every call i have to made accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON) after the path method, like:
path("tokens/{id}",token.getId())
.accept(MediaType.APPLICATION_JSON)
.type(MediaType.APPLICATION_JSON)
.invoke("GET", "")
If i change the order, the accept and type will not take in count

Server 415 Response code

I am using Jetty web server, and Jersey for REST handling.
I defined:
#POST
#Path("/sendMessage")
#Consumes ({MediaType.APPLICATION_XML, MediaType.TEXT_XML})
public Response sendMessage(#Context final UriInfo uriInfo)
{
logger.debug("sendMessage:");
System.out.println("Received POST!");
return Response.status(Response.Status.OK).build();
}
However, when I send a http request, http://localhost:8080/hqsim/sendMessage, the server returns a 415 code.
It's like the call is not allowed. How can I fix this error?
415 means that the media type is unsupported.
The most likely case is that you are either missing the Content-Type header in your request, or it's incorrect. In your case it must be application/xml or text/xml.
If you're using axios, and making;
a) A post request, you should define the request as below
await axios.post("the url you're speaking to",
{the data to post},
{
headers: {"Content-Type": "application/json"}
})
b) A get request;
await axios.get("the url you're speaking to",
{
data: {},
headers: {"Content-Type": "application/json"},
params: {'varX': '34'}
})
where varX is the name of the variable you're sending together with the request
params can as well be empty if you're not sending a query string along.
the url would therefore appear as;
https://myurl.com/?varX=34

Custom Response + HTTP status?

I have a rest interface for my project.
For one class i have a POST method where you can post an xml and i RETURN a custom response like:
<customResponse>Invalid email</customResponse>
if the email from the xml which was posted, was incorrect + other custom messages i have defined for different situations.
For all of these the HTTP STATUS is automatically put on 200 (OK).
Is there any way to change it?
Ps: I know that i can throw a web application like :
throw new WebApplicationException(Response.Status.BAD_REQUEST);
but in this case my custom response is no more included.
So i just want to return my custom error + 400 as http response.
Thanks in advance.
UPDATE after comments:
My method is:
#POST
#Path("{membershipExternalId}")
#Consumes(MediaType.APPLICATION_XML)
#Produces("application/xml")
public CustomResponse invite(){ //code}
You see that i return my CUSTOM RESPONSE. If i would return simple RESPONSE i could set the STATUS but in this case i cannot see any way.
Found the solution:
Put the return type as Response to the method:
#POST
#Path("{membershipExternalId}")
#Consumes(MediaType.APPLICATION_XML)
#Produces("application/xml")
public Response invite(){ //code
if (fail())
return Response.status(400).entity(customResponse).build();
}
Response.status(400).entity(customResponse) will do the trick. When build() it will convert your custom response xml =>
HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
X-Powered-By: Servlet 2.4; JBoss-4.2.3.GA (build: SVNTag=JBoss_4_2_3_GA date=200807181439)/JBossWeb-2.0
Set-Cookie: JSESSIONID=1C72921619A6B32BC1166B3567A39ADA; Path=/
Content-Type: application/xml
Content-Length: 140
Date: Thu, 18 Mar 2010 12:15:15 GMT
Connection: close
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><customResponse><message>Invalid email</message></customResponse>
setStatus or sendError on HttpServletResponse should do the trick.
This is tagged Java but I don't recognize Response.Status.BAD_REQUEST.
For Java just call setStatus on the HttpServletResponse object.
For .NET it looks like this:
HttpContext.Current.Response.StatusCode = xxx;

Categories