I have a front-end react application, where i make a request to a REST Jax-RS backend server.
Here is the request being sent
deletePost = (post) =>{
return deleter(config.restUrl + `posts/${post}`)
}
Here i get the standart URL for my backend, with a 'deleter' function, which is just a standardized fetch delete method (which has also worked with other entities as well).
Here is my Jax-RS resource:
#DELETE
#Consumes(APPLICATION_JSON)
#Produces(APPLICATION_JSON)
#Path("/{id: [0-9]+}")
public Response deletePost(#HeaderParam("authorization") String token, #PathParam("id") Integer id) throws ResourceNotFoundException, AuthenticationException
{
AuthenticationContext authenticationContext = authenticationFacade.authenticateBearerHeader(token);
Post post = postFacade.delete(authenticationContext, id);
return Response.ok(gson.toJson(PostDTO.basic(post))).build();
}
The problem is that it gives me an error saying that the form is HTML/text:
MessageBodyWriter not found for media type\u003dtext/html, type\u003dclass com.group3.sem3exam.rest.dto.PostDTO, genericType\u003dclass com.group3.sem3exam.rest.dto.PostDTO
Since it's implying that it is the PostDTO that has the error, I went to check the basic method, which converts the entity into a Data Transfer Object, to be posted back to the client side.
public static PostDTO basic(Post post)
{
return new PostDTO(
post.getId(),
post.getContents(),
post.getCreatedAt(),
null,
ImageDTO.list(post.getImages(), ImageDTO::withoutUser)
);
}
Here it just calls the method which returns a new instance of the object.
I have not seen this error before, and I'm not sure how to handle it?
Try
return Response.status(Status.OK).entity(new Gson().toJson(PostDTO.basic(post))).build();
Related
I have an endpoint where it supposes to sends a string as a response. My question is do I need to use to response Entity to send string response or just return the string to the consumer?
#GetMapping(value = "/word")
public String getWord() {
String response = "webservice";
return response;
}
Second approach:
#GetMapping(value = "/word", produces ={MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<String> getWord() {
String response = "webservice";
return new ResponseEntity<>(response, HttpStatus.OK);
}
What is the correct approach to send just a string or use response entity?
What is the correct approach to send just a string or use response entity?
The Spring MVC documentation lists a number of types that can be returned from controller methods.
As I previously answered here and here, ResponseEntity<T> represents the entire HTTP response. Besides the body, its API allows you to set headers and a status code to the response.
Returning just a bean instance or a string is fine but doesn't give you much flexibility: In the future, if you need to add a header to the response or modify the status code, for example, you need to change the method return type.
I have a Feign client with a method returning the feign.Response class. When another service throws an exception, feign puts an exception message on response body and puts status, but my service does not throw an exception. Can I throw an exception based on what I received in response like when I use ResponseEntity.
Feign client
#FeignClient(name = "ms-filestorage")
#RequestMapping(value = "/files", produces = "application/json")
public interface FileStorageApi {
#GetMapping(value = "/{id}")
Response getFileById(#PathVariable String id);
}
Usage of client
#Override
public Response getFileFromStorage(String fileId) {
Response fileStorageResponse = fileStorageApi.getFileById(fileId);
// NOW I USE THIS WAY FOR CHECKING RESPONSE BUT IT DOESN'T LOOK GOOD
//if (fileStorageResponse.status() != HttpStatus.OK.value()) {
// throw new OsagoServiceException();
//}
return fileStorageResponse;
}
Usually, if a Feign client call receives an error response from the API it is calling, it throws a FeignException.
This can be caught in a try / catch block (or a Feign ErrorDecoder if you want to be more sophisticated, but that's another post).
However, this is not the case if you map the error response into a Feign.Response return type - see this Github issue.
Instead of returning Feign.Response from getFileFromStorage(), you should create a custom Java object to hold the response, and you will then have access to the FeignException which you can handle as you wish.
Note that if you don't need access to the data that is returned from the API you are calling, changing the return type to void will also resolve this issue.
A REST Service is implemented correctly in SpringMVC, deployed, and returns the correct result string,
#RestController
public class RESTServiceController {
#GET
#Produces("application/json")
#RequestMapping("/restUrl")
public String getResult() {
JSONObject json = new JSONObject();
json.put("result", Boolean.TRUE);
}
}
When testing this Web Service I get the correct output,
{"result":true}
The problem is the caller gets the Response object via CXF, but I don't know how to parse the Response. I don't need a custom object. All I need is the direct string, I just want to see my output string.
String restServiceURI = "http://www.asite.com/restUrl";
WebClient client = WebClient.create(restServiceURI,true);
Response resp = client.get();
//String entity = (String)resp.getEntity; <-- Also tried this to cast to a string
The issue is, the Response length is 0, Status is 302.
The getEntity InputStream brings back an EmptyInputStream based on what the debugger shows.
The Response object doesn't have any info that I can see in the debugger.
How do I just get my direct string back? Is there an example?
You are trying mix both Spring Rest and CxF rest. Either use Spring Rest or CXF Rest.
If you want to use Spring Rest as shown below
#Service
public class RESTServiceController {
#RequestMapping("/restUrl")
public #ResponseBody MyClass getResult() {
return myClass;
}
}
or CXF as shown below.
#Service
public class RESTServiceController {
#GET
#Produces("application/json")
public MyClass getResult() {
return myClass;
}
}
Note: You need not use json conversion explicitly, both Spring Rest and CXF has to feature to convert your object to json string.
However your issue doesn't stop here, I believe you've enabled spring-security, which is sending redirect(302) response, with login page. You can verify response from server by enabling logging in client side.
WebClient.getConfig(client).getInInterceptors().add(new LoggingInInterceptor());
WebClient.getConfig(client).getOutInterceptors().add(new LoggingOutInterceptor());
I have classes auto-generated in NetBeans with RESTful template from entities, with CRUD functions (annotated with POST, GET, PUT, DELETE). I have a problem with create method, which after inserting an entity from the frontend, I would like create to update a response so that my view will automatically (or asynchronously, if that's the right term) reflect the added entity.
I came across this (example) line of code but written in C# (of which I know nothing about):
HttpContext.Current.Response.AddHeader("Location", "api/tasks" +value.Id);
Using JAX-RS in Java, is there anyway to get the current HttpContext just like in C# and to manipulate the header?
The closest I came about is
Response.ok(entity).header("Location", "api/tasks" + value.Id);
and this one certainly is not working. It seems I need to get the current HttpContext before building the Response.
Thanks for your help.
I think you mean to do something like Response.created(createdURI).build(). This will create a response with a 201 Created status, with the createdUri being the location header value. Normally this is done with POSTs. On the client side, you can call Response.getLocation() which will return the new URI.
From the Response API
public static Response.ResponseBuilder created(URI location) - Create a new ResponseBuilder for a created resource, set the location header using the supplied value.
public abstract URI getLocation() - returns the location URI, otherwise null if not present.
Keep in mind about the location you specify to the created method:
the URI of the new resource. If a relative URI is supplied it will be converted into an absolute URI by resolving it relative to the request URI.
If you don't want to rely on static resource paths, you could get the current uri path from the UriInfo class. You could do something like
#Path("/customers")
public class CustomerResource {
#POST
#Consumes(MediaType.APPLICATION_XML)
public Response createCustomer(Customer customer, #Context UriInfo uriInfo) {
int customerId = // create customer and get the resource id
UriBuilder uriBuilder = uriInfo.getAbsolutePathBuilder();
uriBuilder.path(Integer.toString(customerId));
return Response.created(uriBuilder.build()).build();
}
}
This would create the location .../customers/1 (or whatever the customerId is), and send it as the response header
Note if you want to send the entity along with the response, you can just attach the entity(Object) to the method chain of the Response.ReponseBuilder
return Response.created(uriBuilder.build()).entity(newCustomer).build();
#POST
public Response addMessage(Message message, #Context UriInfo uriInfo) throws URISyntaxException
{
System.out.println(uriInfo.getAbsolutePath());
Message newmessage = messageService.addMessage(message);
String newid = String.valueOf(newmessage.getId()); //To get the id
URI uri = uriInfo.getAbsolutePathBuilder().path(newid).build();
return Response.created(uri).entity(newmessage).build();
}
I have this piece of code:
#RequestMapping(value = "/test.json", method = RequestMethod.GET)
#ResponseStatus(HttpStatus.OK)
public #ResponseBody Object[] generateFile(#RequestParam String tipo) {
Object[] variaveis = Variavel.getListVariavelByTipo(tipo);
return variaveis;
}
As far as I know it should take a request to test.json?tipo=H and return the JSON representation of Variavel[], however when I make such request I get:
HTTP Status 406 -
type Status report
message
descriptionThe resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers ()
By using the following function I can get the expected json:
#RequestMapping(value = "/teste.json")
public void testeJson(Model model, #RequestParam String tipo) {
model.addAttribute("data", Variavel.getListVariavelByTipo("H"));
}
What I'm doing wrong?
#RequestBody/#ResponseBody annotations don't use normal view resolvers, they use their own HttpMessageConverters. In order to use these annotations, you should configure these converters in AnnotationMethodHandlerAdapter, as described in the reference (you probably need MappingJacksonHttpMessageConverter).