Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handle Resource not found in Rest API

I am developing a Rest API in spring boot. Which of the following is the best way to handle when an instance of resource not found ?

    @GetMapping(value="/book/{id}")
    public ResponseEntity<Book> getBook(@PathVariable String id){

        Book book = bookService.getBook();

        // Which is best Approach for resource instance not found ?
        if(book == null) {
            // This one
            return new ResponseEntity<>(book, HttpStatus.NO_CONTENT);
            //OR
            return  new ResponseEntity<>(book, HttpStatus.NOT_FOUND);
            //OR 
            throw new DataNotFoundException("Book with id " + id + " Does not exist");
        }

        return new ResponseEntity<>(book , HttpStatus.OK);
    }

I am clear about that when a collection of resource not found in Db then to pass an empty collection instead of null but I am not clear what to do with an instance of resource.

I have also read on StackOverflow that HttpStatus.NOT_FOUND should be used when a Resource under the criteria cannot exist instead of do not exist in the Db.

What is best approach to handle this ?

like image 332
Number945 Avatar asked Nov 03 '18 13:11

Number945


People also ask

How do I fix REST API 404?

You fix this by opening the listen step in your VSM file, and changing the base path in there, so you don't get a 404 error. You could change that to "/api/" so any api requests are dealt-with, or "/api/retrieveId/" so only retrieveId messages are dealt-with, or "/" so all requests are dealt-with.

Should a REST API return 404?

Based on the code above, is it correct to return a NOT_FOUND status ( 404 ), or should I be returning 204 , or some other more appropriate code? If you would expect a resource to be there, because it is looked up using an ID, then a 404 is expected. Something goes wrong, the resource you need to be there is not found.

Why can't I get a resource from the REST API?

If you put in the wrong URI or bad URI that is your problem and the reason you didn't get to a resource whether a HTML page or IMG. Show activity on this post. For this scenario HTTP 404 is response code for the response from the REST API Like 400, 401, 404 , 422 unprocessable entity use the Exception handling to check the full exception message.

What is the error code for REST API?

If the client attempts a resource interaction that is outside of its permitted scope, the REST API should respond with 403. The 404 error status code indicates that the REST API can’t map the client’s URI to a resource. 400 - Bad Request (Client Error) - A json with error \ more details should return to the client.

How to implement a global exception handler for a REST API?

Implement a Global Exception Handler for a REST API with Spring. 2. HTTP Status Codes When a client makes a request to an HTTP server — and the server successfully receives the request — the server must notify the client if the request was successfully handled or not. HTTP accomplishes this with five categories of status codes:

What does Error 404 mean in REST API?

The 404 error status code indicates that the REST API can’t map the client’s URI to a resource. 400 - Bad Request (Client Error) - A json with error \ more details should return to the client.


2 Answers

When working with Spring MVC, you usually have two choices when returning your result, either you work with plain objects, or you work with the ResponseEntity class. Neither of those is better than the other. Additionally, you can decide whether or not you separate your error handling using exceptions or not.

Given that, your third scenario by throwing an exception is essentially the same as one of your first two options. By default, throwing an exception will result into a 500 Internal Server Error, but it can be changed by using the @ResponseStatus annotation, for example:

 @ResponseStatus(HttpStatus.NOT_FOUND) // Or @ResponseStatus(HttpStatus.NO_CONTENT)
 public class DataNotFoundException extends RuntimeException {

 }

Alternatively, you can also define an exception handler. Again, this can be done by either working with plain objects or ResponseEntity, for example:

@ResponseStatus(HttpStatus.NOT_FOUND) // Or @ResponseStatus(HttpStatus.NO_CONTENT)
@ExceptionHandler(DataNotFoundException.class)
public Book handleNotFound(DataNotFoundException ex) {
    return null;
}

Or:

@ExceptionHandler(DataNotFoundException.class)
public ResponseEntity<Book> handleNotFound(DataNotFoundException ex) {
    return new ResponseEntity<>(null, HttpStatus.NOT_FOUND); // Or HttpStatus.NO_CONTENT
}

Again, neither is better than the other and what you choose is mostly based upon personal preference. However, you should probably use one consistently.


Now, that means that there are still two choices left, either by choosing HttpStatus.NOT_FOUND (404) or HttpStatus.NO_CONTENT (204). While you can technically use either status, they have a different meaning:

  • 204 = The request was succesful, but there's nothing.
  • 404 = The request was not succesful, the resource does not exist

Now, if you request /book/123 and there's no book with ID 123, it could be seen as a resource that doesn't exist, and thus, HttpStatus.NOT_FOUND makes most sense.

like image 53
g00glen00b Avatar answered Oct 13 '22 15:10

g00glen00b


First of all I think that you mean @PathVariable and not @RequestParam for your method parameter (see difference between PathVariable and RequestParam here ).

Secondly, it will be ambiguous for the client that receives the 404 not found response as this means that :

The server has not found anything matching the requested address (URI) ( not found ). This means the URL you have typed is wrong or obsolete and does not match any document existing on the server (you may try to gradualy remove the URL components from the right to the left to eventualy retrieve an existing path).

Knowing that your return type is a ResponsEntity, it will be more appropriate to have this :

    @GetMapping(value="/book/{id}")
    public ResponseEntity getBook(@PathVariable String id){

        Optional<Book> book = bookService.getBook();

        if(book.isPresent()) {
            return ResponseEntity.status(HttpStatus.OK).body(book.get());
        }

        return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
    }
like image 26
Abdelghani Roussi Avatar answered Oct 13 '22 15:10

Abdelghani Roussi