How to catch what is POST'ed to rest api - spring

I have a rest api set up at api/books, and one can send a new book object there, and it will be added to the database. The guestion is, how can I correctly catch what is being POST'ed, so one can for example, validate what is being sent?
#RequestMapping(value="/api/books", method = RequestMethod.POST)
public String bookSavePost(#RequestBody Book book) {
bookRepository.save(book);
return "redirect:/api/books";
}
This works, as in it saves the book and I can catch what the user sends, but with this enabled, it overrides the default REST method, which doesn't allow one to actually view the api anymore. If I change this particular method to GET, it returns a string "redirect:/api/books", so it doesn't even redirect anything. Is there some way to actually redirect it to the rest api endpoint?

You can write your own reuquest Interceptor .
Spring provides HandlerInterceptor class :
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/HandlerInterceptor.html
Here is a quick sample how to do this:
https://www.baeldung.com/spring-mvc-handlerinterceptor

A redirect requires three two things to be successful: A HTTP code of 301 or 302 AND a location header that includes the endpoint to which you want the client to visit.
E.g., in the headers section you should have
location: '/correct/endpoint'

Related

Spring MVC - Error handling with redirect if download not possible

in my Spring Boot application you can download some documents, by pressing a button. This leads to the following user experience: If the user presses the button, either a download is triggered or nothing happens.
Currently, the backend is either returning the bytes or 404:
#GetMapping("/download")
public ResponseEntity<byte[]> download() {
Optional<byte[]> data = service.getDocumentData();
return data.map(bytes -> new ResponseEntity<>(bytes, headers(), OK))
.orElseGet(() -> ResponseEntity.notFound().build());
}
Now we want to achieve, that the user is redirected to an error page, if no file can be downloaded.
With Spring MVC I would just return the error template like
public String notFound() {
return "error/404"; // the custom template
}
But now I need to mix two different concerns. Returning template or returning a ResponseEntity. For this i stumbled above the following answer, which uses Generics. However, I don't think its a good practice. So i thought about other ways.
My first idea was to use HTTP location header for redirecting on the frontend side, but I never used it before. Do you think this is a good way? Do you have other ideas?
Suggestion 1:
In the download() method, add HttpServletResponse response as the parameter and call response.sendRedirect("http://somewhere/404.html"); when the document requested is not found.
In addition, you can also change the status code in the response as response.setStatus(HttpServletResponse.SC_NOT_FOUND);
Suggestion 2:
Throw a custom exception, for e.g. FileNotFoundException and handle the exception in the #ExceptionHandler to return the error page in the ResponseEntity.
Refer - https://howtodoinjava.com/spring-core/spring-exceptionhandler-annotation/

How can I avoid deserealization in microservise?

I'm developing microservise which receives HTTP POST requests and then redirects them to another destination point in order to receive response, handle it and hand it to another system.
My question is - how can I avoid deserealization while receiving these requests? The microservice don't handle incoming JSONs. From the performance point of view, it's better to avoid deserealization.
I heard I can use Nginx or Apache but how can I embed them into the microservice?
Is there any proven solution? Just don't want to invent a bicycle.
I don't know what is the technology stack you are using (programming language, framework.. etc) but I suppose that in all of them is a way to recieve incoming rest requests without need to deserialize the body.
For example in a java/spring scenario you can define in the corresponding controller method the body parameter as string and in this case there isn't any deserialization of the body, the method will recieve it as a plain string so you can forward it as is to the other service:
#PostMapping(value = "/path")
public ResponseEntity controllerMethod(#RequestBody String body) {
// your code here
}

which crud operation in rest to use post or delete?

i have created a bank application where i want to write a rest service to delete account . so for that we need an account no . for that i think for security reasons i cant pass account no in url . so i am passing it in request body . i think if i try using it with delete it runs fine but again that could be a security issue .
so in that case will i need to use post instead of delete so that i can pass account no in request body ?
#PostMapping("/account")
public void deleteAccount(#RequestBody #Valid final AccountNoDto accountNoDto) {
return accountService.deleteAccount(accountNoDto);
}
or
#DeleteMapping("/account/{accountNo}")
public void deleteAccount(#PathVariable Long accountNo) {
return accountService.deleteAccount(accountNo);
}
You should use #DeleteMapping because you are deleting a record.
The HTTP verbs should be compliant with what the function does.
But dont send the account Number along with the endPoint.
Write the endpoint as -
#DeleteMapping("/account")
The Account Number should be retrived at the backend from the token you will be sending along with the request.So All requests GET,POST,PUT,DELETE will have the same uri and the account number will be fetched from the token at the backend.
If you want to know how it is done in spring read about SecurityContextHolder class
Idealy we use #DeleteMapping for delete operation and we use #PostMapping for new creation and updation of data . I dont think account id is that much sensitive information to reveal in url. You can go for #DeleteMapping

Getting information for rest template

I have seen a lot of code that uses this getForObject() method that takes a URI and replaces things in {} with the numbers at the end of the method.
My question is: what exactly IS http://localhost:8080/spring-rest/foos? Is it a file of some sort? What would it look like in this context.
In your example:
Foo foo = restTemplate.getForObject(URI, Foo.class, "1");
is actually trying to GET a REST resource with an HTTP request.
Under the covers:
The URL template is rendered to http://localhost:8080/sping-rest/foos/1
The HTTP client issues a GET request to http://localhost:8080/sping-rest/foos/1
The REST service can respond with a JSON representation of that resource, such as {"id":1,"content":"Hello, World!"}
The HTTP client converts that JSON response into an instance of Foo.class (using message converters)
You get an instance of Foo!
The spring.io website lists a lot of guides, you should definitely check them out! There's even a "Consuming a RESTful web service" guide.

How to call the WebApi,Implemented with AttributeRouting for each action methods,calling it from my client and passing the Query parameters in url?

I have implemented attribute routing for each of action methods in My Webapi.
Example of action method is:-
[Route("api/DocumentApi/DeleteDocument/{fileInfoId}/{customerAccountName}")]
[HttpDelete]
public HttpResponseMessage DeleteDocument(int fileInfoId, string customerAccountName)
{
//***
//*** Some body contents
//***
}
Now i want to call the above action method from the client example( Fiddler Web debugger),or browser and want to pass the Url request in the below pattern:-
http://{localhost:9791}/api/DocumentApi/DeleteDocument?fileInfoId=12&customerAccountName="Manish"
Currently i am not able to hit the above action method by the above specified url request.
But if i use the url pattern like below:-
http://{localhost:9791}/api/DocumentApi/DeleteDocument/12/Manish
I am able to hit the above action method.But for my project requirement,I need to use the Url with query parameters only.
Please suggest me the approach,how to achieve this?
Any response will be greatly appreciated.
Route templates in Web API do not support specifying query string parameters. For your scenario, do not define fileInfoId and customerAccountName as part of your route template as doing so makes Web API to strictly look for 5 segments(the text between the / characters in your route template) in your request url...so just modify your route template to [Route("api/DocumentApi/DeleteDocument")] and keep the parameters on the actions as it is...
Use like following code :
[Route("api/DocumentApi/DeleteDocument/{fileInfoId}/{customerAccountName}")]
public HttpResponseMessage TestAction(string fileInfoId,string customerAccountName)
{

Resources