0

I want to return a string (json string) from a spring controller as response to AJAX call it receives, the response could different based on whether or not I have a @Valid form submitted. This is how I am handling it and wanted to find out if this is considered as best practice? Please note I am using @RestController so @ResonseBody applies all methods.

    @RequestMapping(value = "/save" , method = RequestMethod.POST)
public String saveScheduledAlert(@Valid ScheduledAlertForm scheduledAlertForm, BindingResult bindingResult) {
    StringBuilder jsonString = new StringBuilder();
    if(bindingResult.hasErrors()){
        jsonString.append("{\"success\" : \"false\"");
        for(ObjectError error : bindingResult.getAllErrors())
            jsonString.append(",\"").append(((FieldError) error).getField()).append("\":\"").append(error.getDefaultMessage()).append("\"");
    } else {
        //save the data
        jsonString.append("{\"success\" : \"true\"");
    }

    jsonString.append("}");
    return jsonString.toString();


}
Toseef Zafar
  • 1,601
  • 4
  • 28
  • 46

3 Answers3

3

Old question but for anyone else that needs help with this, I use a custom ApiResponse class for this. My class looks like this:

public class ApiResponse<T> {
    String message;
    int statusCode;
    T data

    //....getters and setters

This way, I can use "SUCCESS" or "ERROR" as the message, the appropriate HttpStatus code and then any Type as my data I want to send.

Then, in the controller, I just do this:

@PostMapping("/sign-up")
public ResponseEntity<String> signUp(@RequestBody Account account) {
  
  if (accountService.getAccountByEmail(account.getEmail()) != null) {
      ApiResponse<String> apiResponse = new ApiResponse<>("A user with that email  
          already exist", HttpStatus.CONFLICT.value(), null);
         return new ResponseEntity<String>(new Gson().toJson(apiResponse), HttpStatus.CONFLICT);
  }

 // ... rest of controller code 

As you can see, I use the Gson dependency to create my JSON String.

Ojonugwa Jude Ochalifu
  • 26,627
  • 26
  • 120
  • 132
2

so basically what you want to do is generating 2 pojos

public class RestWrapperDTO {
    protected boolean success;
    public boolean isSuccess() {
        return success;
    }
    public void setSuccess(boolean value) {
        success = value
    }
}

and a another error DTO

public class RestErrorDTO extends RestWrapperDTO {
    private Map<String, String> errors;

    public Map<String, String> getErrors() {
        return errors;
    }
    public void setErrors(Map<String, String> value) {
        errors = value
    }
}

and your controller

@RequestMapping(value = "/save" , method = RequestMethod.POST)
public RestWrapperDTO saveScheduledAlert(@Valid ScheduledAlertForm scheduledAlertForm, BindingResult bindingResult) {
    StringBuilder jsonString = new StringBuilder();

    if(bindingResult.hasErrors()){
        RestErrorDTO errorDTO = new RestErrorDTO();
        // fill map with errors here
        return errorDTO;
    } else {
        RestWrapperDTO wrapperDTO = new RestWrapperDTO();
        wrapperDTO.setSuccess(true);
        return wrapperDTO;
    }
}

it is not the most sufficient code, but it should help you :D

if you are using a simple @Controller annotation - what you are looking for is the @ResponseBody-annotation

or if you use @RestController than this is already available

You can simply return an object with the interface Serializable - a simple POJO and spring will handle the rest.

For further readings:

Simon Schrottner
  • 4,146
  • 1
  • 24
  • 36
  • I already have ResonseBody applied to all methods as I am using @RestController, futher more what I want to do is just return success : true if all went well or send the success : false and then validation errors as key value pairs in json thats all. – Toseef Zafar Jun 20 '17 at 09:33
  • basically i have the explanation and @nick savenia the code example – Simon Schrottner Jun 20 '17 at 09:34
  • my recommendation, – Simon Schrottner Jun 20 '17 at 09:36
  • I thought of return Object previously but was wondering how would I send a success : false message to find out at client that something went wrong? – Toseef Zafar Jun 20 '17 at 09:37
  • thanks, that makes sense but why should I not use just one class with a boolean flag and a Map for errors? wouldn't that be simple enough? – Toseef Zafar Jun 20 '17 at 09:51
  • Yeah for your usecase yes... But what if you want to have more objects with that success flag – Simon Schrottner Jun 20 '17 at 09:55
  • ok cool, I am mark your answer as correct answer to my question, one last question: is that the best "Spring way" of return json to ajax requests? or there is no standard way and it all depends on use cases? – Toseef Zafar Jun 20 '17 at 10:00
  • in my opinion it is the best way to return json objects and it is the standard way for returning objects also for xml, there is an on XMLMessageConverter etc. – Simon Schrottner Jun 20 '17 at 10:10
  • In ajax request e.g. JQuery ajax, the above controller method will always fall in success handler right? and based on success value of "success" I will render response, and the error handler of JQuery ajax will be for exceptions etc, is that right way of thinking about ajax success and failure handlers? – Toseef Zafar Jun 20 '17 at 10:21
0

create a POJO as given below:

public class SuccessPOJO{
private String success;

.....
getters and setters
.....
}

Now you can set values of success message and return this SuccessPOJO object. In the browser you will receive a JSON formatted object with success message!

R Dhaval
  • 536
  • 1
  • 9
  • 21