2014-12-08 6 views
5

Ho un API RESTFul che consuma/restituisce JSON nel corpo della richiesta/risposta. Quando il client invia dati non validi (JSON valido ma valori non validi per i campi), desidero poter restituire una struttura JSON (oltre al codice 400+ pertinente).In Java, come posso restituire errori formattati JSON significativi dalla convalida Resteasy?

Questa struttura consentirebbe quindi al frontend di analizzare gli errori per ogni campo e rendere gli errori accanto ai campi di input.

E.g. Uscita ideale:

{ 
    "errors":{ 
    "name":["invalid chars","too long","etc"] 
    "otherfield":["etc"] 
    } 
} 

Sto usando Resteasy per l'API, e usare le eccezioni di violazione è abbastanza facile per farlo rendere errori JSON:

@Provider 
@Component 
public class ValidationExceptionHandler implements ExceptionMapper<ResteasyViolationException> { 
    public Response toResponse(ResteasyViolationException exception) { 
     Multimap<String,String> errors = ArrayListMultimap.create(); 

     Consumer<ResteasyConstraintViolation> consumer = (violation) -> { 
      errors.put(violation.getPath(), violation.getMessage()); 
     }; 

     exception.getParameterViolations().forEach(consumer); 

     Map<String, Map<String, Collection<String>>> top = new HashMap<>(); 

     top.put("errors", errors.asMap()); 

     return Response.status(Status.BAD_REQUEST).entity(top) 
       .build(); 
    } 
} 

Tuttavia, i percorsi di errore (violation.getPath()) sono proprietà -centrico piuttosto che XmlElement-name-centric.

E.g. le uscite di cui sopra:

{ 
    "errors":{"createCampaign.arg1.name":["invalid chars","etc"]} 
} 

ho cercato di strippaggio l'indice di ritorno da l'ultimo punto per ottenere "nome", ma ci sono altri problemi con questo hack.

E.g. se il mio "nome" la proprietà non è "nome" non funziona:

@XmlElement(name="name") 
@NotNull 
private String somethingelse; 

"somethingelse" sarà restituito al cliente, ma cliente non ha idea di cosa si tratta:

{ 
    "errors":{"somethingelse":["cannot be null"]} 
} 

Il client vuole "nome" poiché è quello che il campo è stato chiamato quando lo hanno inviato.

mia risorsa:

package com.foo.api; 

import org.springframework.stereotype.Service; 
import javax.validation.Valid; 
import javax.ws.rs.Consumes; 
import javax.ws.rs.POST; 
import javax.ws.rs.Path; 
import javax.ws.rs.Produces; 
import javax.ws.rs.core.MediaType; 
import com.foo.dto.CarDTO; 

@Service 
@Path("/car") 
public class CarResource { 

    @POST 
    @Produces({MediaType.APPLICATION_JSON}) 
    @Consumes(MediaType.APPLICATION_JSON) 
    public CarDTO create(
      @Valid CarDTO car 
    ) { 
     //do some persistence 
     return car; 
    } 
} 

esempio dto:

package com.foo.dto; 

import javax.validation.constraints.NotNull; 
import javax.validation.constraints.Min; 
import javax.validation.constraints.Max; 
import javax.xml.bind.annotation.XmlElement; 

public class CarDTO { 
    @Min(1) 
    @Max(10) 
    @NotNull 
    @XmlElement(name="gears") 
    private int cogs; 
} 

risposta

1

This article descrive abbastanza bene quello che devi fare.

Fondamentalmente è necessario implementare uno ExceptionMapper.

@Provider 
public class ValidationExceptionMapper implements ExceptionMapper<ValidationException> { 

    @Override 
    public Response toResponse(ValidationException exception) { 
     Response myResponse; 
     // build your Response based on the data provided by the exception 
     return myResponse; 
    } 

} 
0

un messaggio di errore personalizzato può essere utilizzato in modo da wouldnt bisogno di guardare il percorso

@NotNull(message="name cannot be null") 
Problemi correlati