Brett Freeman
Brett Freeman

Reputation: 691

How do you return an error response from a binding result validation failure?

I am trying to get the validation message from a form object validation failure, put the message into an error response and return it but I havn't been able to figure out how looking at alot of articles and github repos...

ProductController.java

@PostMapping("/products")

    public ProductResponse createProduct(@Validated @RequestBody ProductForm productForm, BindingResult bindingResult) {

//trying to make the code below work but I get an "incompatible type" error.

        if (bindingResult.hasErrors()) {
            List<String> errors = bindingResult.getAllErrors().stream().map(e -> e.getDefaultMessage()).collect(Collectors.toList());
            return new ErrorResponse("404", "Validation failure", errors);
        }

        Product product = productForm.convertToProduct();
        Product createdProduct = productRepository.save(product);
        return new ProductResponse(createdProduct, "Product created");
    }

ErrorResponse.java

package com.assignment.restapi.web.response;


import java.util.ArrayList;
import java.util.List;

public class ErrorResponse {

    private String statusCode;
    private String errorContent;
    private List<String> messages;

    public ErrorResponse(String statusCode, String errorContent, String messages) {
        this.statusCode = statusCode;
        this.errorContent = errorContent;
        this.messages = new ArrayList<>();
        this.messages.add(messages);
    }

    public ErrorResponse(String statusCode, String errorContent, List<String> messages) {
        this.statusCode = statusCode;
        this.errorContent = errorContent;
        this.messages = messages;
    }

    public String getStatusCode() {
        return statusCode;
    }

    public void setStatusCode(String statusCode) {
        this.statusCode = statusCode;
    }

    public String getErrorContent() {
        return errorContent;
    }

    public void setErrorContent(String errorContent) {
        this.errorContent = errorContent;
    }

    public List<String> getMessages() {
        return messages;
    }

    public void setMessages(List<String> messages) {
        this.messages = messages;
    }
}

ProductForm.java

package com.assignment.restapi.web.view;

import com.assignment.restapi.domain.Product;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;

public class ProductForm {

    String productImage;

    @NotBlank(message = "cannot be blank")
    @Size(max = 100, message = "has to be over 100 characters")
    String productTitle;

    @Size(max = 500, message = "has to be over 500 characters")
    String productDescription;

    @Min(value = 1, message = "has to be larger than 1")
    Integer productPrice;

    public ProductForm() {

    }

    public ProductForm(String productImage, String productTitle, String productDescription, Integer productPrice) {
        this.productImage = productImage;
        this.productTitle = productTitle;
        this.productDescription = productDescription;
        this.productPrice = productPrice;
    }

    public String getProductImage() {
        return productImage;
    }

    public void setProductImage(String productImage) {
        this.productImage = productImage;
    }

    public String getProductTitle() {
        return productTitle;
    }

    public void setProductTitle(String productTitle) {
        this.productTitle = productTitle;
    }

    public String getProductDescription() {
        return productDescription;
    }

    public void setProductDescription(String productDescription) {
        this.productDescription = productDescription;
    }

    public Integer getProductPrice() {
        return productPrice;
    }

    public void setProductPrice(Integer productPrice) {
        this.productPrice = productPrice;
    }

    //turns productForm into Product object.
    public Product convertToProduct() {
        //step by step debug mode, new object constructor function in Product.java gets called.
        //setter methods get called and values of the ProductForm object gets passed and becomes the new value of the Product object.
        Product product = new Product();
        product.setProductTitle(this.productTitle);
        product.setProductImage(this.productImage);
        product.setProductDescription(this.productDescription);
        product.setProductPrice(this.productPrice);
        return product;
    }
}

Any idea how I can return a ErrorResponse when there is a validation error on the form object?

Was thinking to create an class that extends both ErrorResponse and a ProductResponse class so that I won't get the error "incompatible types."

Upvotes: 1

Views: 5367

Answers (1)

narayan-sambireddy
narayan-sambireddy

Reputation: 335

The reason why you are getting "incompatible type" is the method is expected to return "ProductResponse" but you are trying to return "ErrorResponse". This can be fixed by using ResponseEntity.

@PostMapping("/products")
public ResponseEntity<Object> createProduct(@Validated @RequestBody ProductForm productForm, BindingResult bindingResult) {
    //trying to make the code below work but I get an "incompatible type" error.

    if (bindingResult.hasErrors()) {
        List<String> errors = bindingResult.getAllErrors().stream().map(e -> e.getDefaultMessage()).collect(Collectors.toList());
        // Here you can change ok to badRequest depending on your use case.
        return ResponseEntity.ok(new ErrorResponse("404", "Validation failure", errors));
        // In case if you want to fail the request, you need to use the below: 
        // return ResponseEntity.badRequest().body(new ErrorResponse("404", "Validation failure", errors));
    }

    Product product = productForm.convertToProduct();
    Product createdProduct = productRepository.save(product);
    return ResponseEntity.ok(new ProductResponse(createdProduct, "Product created"));
}

Upvotes: 1

Related Questions