Link to home
Start Free TrialLog in
Avatar of Software Programmer
Software Programmer

asked on

Will the idempotent will be resolved when manually handling the use case ?

Assume we have the following code

@RestController
@RequestMapping("books", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public final class BookController {
 
  private final Map<String, Book> books = new HashMap<>();
 
  @PostMapping
  public ResponseEntity<Book> addBook(@RequestParam String title, @RequestParam String authorName) {
    String id = generateId();
    Book book = new Book(id, title, authorName);
    books.put(id, book);
    return ResponseEntity.created(URI.create("/books/" + id)).body(book);
  }
 
  @GetMapping
  public ResponseEntity<Book> getBook(@PathVariable String id) {
    Book book = books.get(id);
    if (book == null)
      return ResponseEntity.notFound().build();
 
    return ResponseEntity.ok(book);
  }
 
  @PutMapping
  public ResponseEntity<Book> updateBook(@PathVariable String id, @RequestParam String title, @RequestParam String authorName) {
    Book book = books.computeIfPresent(id, book -> book.withTitle(title).withAuthorName(authorName));
    if (book == null)
      return ResponseEntity.notFound().build();
 
    return ResponseEntity.ok(book);
  }
 
  @DeleteMapping
  public ResponseEntity<Book> removeBook(@PathVariable String id) {
    Book book = map.remove(id);
    if (book == null)
      return ResponseEntity.notFound().build();
 
    return ResponseEntity.ok(book);
  }
}


If I request DELETE /books/bbcff625a88e45fcaf28f2a535997982 twice in succession, the first time it may delete a book and return status code 200, and the second time it must not delete anything, but it may return status code 404.

Assume i am verifying whether the record exist and throw an exception. then status code automatically changes..

In such a case, i don't need to worry about the idempotent. is that right ?? i can safely use the DELETE where it gives a consistent status codes.
Avatar of girionis
girionis
Flag of Greece image

DELETE is idempotent in the sense that the action will affect the resource only once, no matter how many times you run it. The book will only be deleted once. The status codes will indeed be 200 the first time (when the book is deleted) and 404 (the second time).

Having said that, you do not need to throw an exception, you only need to return 404 when the book is not found (like you do in your code). You might also want to return a 204 (No content) the first time you delete the book (no need to return 200 and the entity itself). 204 means that the server successfully processed your request and is not returning any content.

In such a case, i don't need to worry about the idempotent. is that right ??

Yes it is right.
Avatar of Software Programmer
Software Programmer

ASKER

So we need to handle 404 (the second time) in the front end. Also, 204 in the front-end. However 404 is not found is a generic error. my question is instead of sending 404 error code, can i send a custom code so that it will be processed differently. Ex: Entity not found. Since planning to handle everything in controller advice. Will it be a best practice to change the error code ? as there is no way we can differentiate 404 for multiple request with each as a different meaning. may be page not found

Please advise.
Why can you not differentiate 404 for different requests? 404 for a DELETE means the resource to be deleted cannot be found. 404 for a GET means the resource to be retrieved cannot be found. It does have a generic meaning, that the resource cannot be found, but each time the operation is different so the context changes.

The client knows the request it sends is DELETE or GET, so it should act differently on a 404 from DELETE and on a 404 from GET.

There is one more code that you could use: 410. 410 means gone for good (in contrast to 404 which means that is not found, but it might be found in the future). When the client receives a 410 it should not repeat the same request again.

Of course if none of the codes above does exactly what you want to do, you might as well send your own codes.
Assume we are throwing an exception in all service layer and catching the business and other exceptions in controller advice. Do we need to change the status so that business exceptions are handled differently in front end ???

Many uses controller advice. does using controller advice is mainly to avoid logging in tomcat logs and sending the error to application log ???
Assume we are throwing an exception in all service layer and catching the business and other exceptions in controller advice. Do we need to change the status so that business exceptions are handled differently in front end ???

You do not need to, but you can if you want. If for example you throw a BookNotFoundException from your service layer, and you have the following advice

@ControllerAdvice
class ExceptionHandler {
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(BookNotFoundException.class)
    public void handleNotFound() {

    }
}

Open in new window


this means that the error.jsp will be called and the response status will be 404. This will apply to all BookNotFoundExceptions from all your controllers.

Many uses controller advice. does using controller advice is mainly to avoid logging in tomcat logs and sending the error to application log ???

No. You use a controller advice because you want to handle specific exceptions (lets say a BookNotFoundException) from all your controllers. So instead of handling the BookNotFoundException in each controller separately, you create an advice and you handle it there.
I am talking about the parameters being sent.....Assume BookNotFoundException...

We would say Booking doesn't exist for booking number 123 in one service method. In another service method. we would say Booking doesn't exist for user abc. in another service method we would say booking doesn't exist for the company thb. for the same exception we would pass three parameters.

Now instead of having try and catch in all controllers ...we just have one advice to catch and set response status and response message and response type in the same...Similarly for any warning exception....

Is that right ??? Please correct me in detail if i am wrong
I am not sure I understand what you want to do. Do you want to log different messages based on the user type?
The problem is where i will formulate the error message text with parameters

Example, Assume file not found exception is thrown for the given file name

Generally, in message.properties file we will be having text as File Doesn't Exist for file {0}

The translation of error message usually happens in the presentation layer.....

Now if we need to pass the error message so that controller advice takes care of passing it to the UI....

Do we need to construct the error message in the service layer before sending ??? Where the exception and the parameters will be binded ???

for example

public void accessFile(String fileName) {
  File file = new File(fileName);
  if(!file.exists()) {
       throw new FileNotFoundException(Constants.FILE_NOT_FOUND.....);
       How to construct the error message with property key and sending with proper error message binded with exception????
      so that in controller advice we would just use exception.getMessage() which will have the translated text.

   }
}

Please let me know if you don't understand what i expect.
ASKER CERTIFIED SOLUTION
Avatar of girionis
girionis
Flag of Greece image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial