31

I'm trying to have a @RestController which takes a @PathVariable return a specific object in JSON format, along with proper status code. So far the way the code is, it will return the object in JSON format because it is using Spring 4 built in Jackson library by default.

However I do not know how to make it so it will give a message to the user saying we want an api variable, then JSON data, then Error code (Or success code depending if all went well). Example output would be:

Please enter api value as parameter (NOTE this can be in JSON as well if needed)

{"id": 2, "api": "3000105000" ... } (NOTE this will be the JSON response object)

Status Code 400 (OR proper status code)


The url with parameter look like this

http://localhost:8080/gotech/api/v1/api/3000105000

The code I have so far:

@RestController
@RequestMapping(value = "/api/v1")
public class ClientFetchWellDataController {

    @Autowired
    private OngardWellService ongardWellService;

    @RequestMapping(value = "/wells/{apiValue}", method = RequestMethod.GET)
    @ResponseBody
    public OngardWell fetchWellData(@PathVariable String apiValue){
        try{
            OngardWell ongardWell = new OngardWell();
            ongardWell = ongardWellService.fetchOneByApi(apiValue);
    
            return ongardWell;
        }catch(Exception ex){
            String errorMessage;
            errorMessage = ex + " <== error";
            return null;
        }
    }
}
1
  • Minor objection, but it looks like the code says the url should end with /api/v1/wells/{apiValue}, not /api/v1/api/{apiValue} Commented Dec 5, 2018 at 15:51

2 Answers 2

64

A @RestController is not appropriate for this. If you need to return different types of responses, use a ResponseEntity<?> where you can explicitly set the status code.

The body of the ResponseEntity will be handled the same way as the return value of any @ResponseBody annotated method.

@RequestMapping(value = "/wells/{apiValue}", method = RequestMethod.GET)
public ResponseEntity<?> fetchWellData(@PathVariable String apiValue){
    try{
        OngardWell ongardWell = new OngardWell();
        ongardWell = ongardWellService.fetchOneByApi(apiValue);

        return new ResponseEntity<>(ongardWell, HttpStatus.OK);
    }catch(Exception ex){
        String errorMessage;
        errorMessage = ex + " <== error";
        return new ResponseEntity<>(errorMessage, HttpStatus.BAD_REQUEST);
    }
}

Note that you don't need @ResponseBody on a @RequestMapping method within a @RestController annotated class.

Sign up to request clarification or add additional context in comments.

Comments

32

The idiomatic way would be to use an exception handler instead of catching the exception in your regular request handling method. The type of exception determines the response code. (403 for security error, 500 for unexpected platform exceptions, whatever you like)

@ExceptionHandler(MyApplicationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public String handleAppException(MyApplicationException ex) {
  return ex.getMessage();
}

@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String handleAppException(Exception ex) {
  return ex.getMessage();
}

3 Comments

mmmmm kinda makes sense, so where would my existing code go in all this? Or is the code you posted its own thing that i will call to handle my exceptions? Sorry I've never seen code like that before, looks very useful though so thanks for the help
It goes in the same controller as your code. Just take the try-catch out of the handler method.
This is very useful and better way of writing RestAPIs I think. If I have multiple controllers, do I have to write these handlers for all controllers or can I put these in base class or in interface and use it?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.