¿En qué capa debe ubicarse la validación?

18

Estoy creando una API Rest usando Spring Boot y estoy usando Hibernate Validation para validar entradas de solicitud.

Pero también necesito otros tipos de validación, por ejemplo, cuando los datos de actualización deben verificarse, si la identificación de la empresa no existe, quiero lanzar una excepción personalizada.

¿Debería esta validación ubicarse en la capa de servicio o en la capa de controlador?

Capa de servicio:

 public Company update(Company entity) {
    if (entity.getId() == null || repository.findOne(entity.getId()) == null) {
        throw new ResourceNotFoundException("can not update un existence data with id : " 
            + entity.getId());
    }
    return repository.saveAndFlush(entity);
}

Capa de controlador:

public HttpEntity<CompanyResource> update(@Valid @RequestBody Company companyRequest) {
    Company company = companyService.getById(companyRequest.getId());
    Precondition.checkDataFound(company, 
        "Can't not find data with id : " + companyRequest.getId());

    // TODO : extract ignore properties to constant

    BeanUtils.copyProperties(companyRequest, company, "createdBy", "createdDate",
            "updatedBy", "updatedDate", "version", "markForDelete");
    Company updatedCompany = companyService.update(company);
    CompanyResource companyResource = companyAssembler.toResource(updatedCompany);
    return new ResponseEntity<CompanyResource>(companyResource, HttpStatus.OK);
}
fdarmanto
fuente

Respuestas:

8

Tanto la capa de controlador como la capa de servicio exponen ciertas interfaces. Las interfaces definen contratos sobre cómo se debe usar la interfaz. Contrato generalmente significa qué argumentos (y sus tipos y valores) se esperan, qué excepciones se pueden lanzar, qué efectos secundarios se crean, etc.

Ahora, su validación es esencialmente la aplicación del contrato del método de actualización del controlador () y el método de actualización de la capa de servicio (). Ambos tienen un contrato muy similar, por lo que sería natural que la validación (cumplimiento del contrato) también fuera común.

Una posible forma de hacerlo es separar la validación de este contrato y hacer que se llame en ambas capas. Esto suele ser más claro: cada clase / método hace cumplir su propio contrato, pero a menudo no es práctico debido al rendimiento (acceso a la base de datos) u otras razones.

Otra posibilidad es delegar esta validación a la capa de servicio mientras se define explícitamente el comportamiento en caso de validación fallida en el contrato de la capa de servicio. La capa de servicio generalmente devolverá algún error de validación genérico (o una excepción de lanzamiento) y la capa del controlador querrá reaccionar de alguna manera específica al error; en este caso, devolveremos 400 Solicitudes incorrectas para señalar que la solicitud entrante no era válida.

En este diseño, existe el peligro de un acoplamiento excesivo entre la lógica empresarial en la capa de servicio (que debería ser bastante genérica) y el controlador (que maneja la lógica de integración).

De todos modos, esta es una pregunta bastante controvertida y 100 personas responderán con 100 respuestas. Esta es solo mi opinión al respecto.

qbd
fuente
1

La entrada debe verificarse en la capa de servicio.

Y "No se puede encontrar la identificación" es una condición de error lógico. Por lo tanto, debe arrojarse desde la capa del controlador.

Esto nuevamente depende de su diseño / capas.
Qué se supone que debe hacer una capa de servicio y qué se espera de la capa de controlador.

Sin papel
fuente
Una respuesta no debería estar buscando aclaraciones adicionales de la pregunta. Si la pregunta necesita aclaración, debe comentarse y posiblemente marcarse para su cierre si no está muy clara. Sí, me doy cuenta de que no tienes la reputación de ninguna de esas acciones.
La "comprobación de entrada" es ambigua. Por ejemplo, podría poner un atributo Requerido en un campo para indicar que debe completarse, pero también podría poner un atributo personalizado complejo que verifique, por ejemplo, que un valor de campo es mayor que otro. En mi humilde opinión, la validación Comparar "huele" mucho más a la capa de servicios empresariales que a la capa de controlador.
JustAMartin
1

Las validaciones de Hibernate son verificaciones sobre la integridad de los datos. Para evitar RuntimeExceptions de bbdd. Son prácticamente las mismas validaciones que debes controlar con Restrains . Debido a que solo la capa empresarial debe alimentar la capa de persistencia, usted puede (o no, depende de usted) confiar en la exactitud de los datos que provienen de su capa empresarial

No pongo validaciones en DAO. Espero datos válidos de las capas superiores. En caso de error, delego al bbdd la responsabilidad de conocer su contenido.

Luego vienen las validaciones en la capa empresarial. Todas las validaciones comerciales se centraron en mantener la coherencia de los datos, no su integridad .

Finalmente hago validaciones previas en la capa de control. Los relacionados solo con dicha capa.

Pronto verá qué validaciones están destinadas a implementarse en la capa empresarial. El más común: control de identificación. Este se puede implementar fácilmente en ambas capas. Si espera que muchos controladores o clientes consuman su capa empresarial, en lugar de repetir la misma validación en todas partes, será un excelente candidato para la capa empresarial.

A veces los controladores tienen sus propias reglas y condiciones que no se reproducirán en ninguna otra fachada. Entonces es un candidato para ser puesto en dicho controlador.

Piense en lo que está validando y si desea aplicarlo para todos sin importar qué. O si se trata de una validación contextual ("Estoy validando algo que solo sucede en una fachada de control / vista particular).

Laiv
fuente
0

En nuestra tienda de Java, hemos dividido intencionalmente la validación de widgets web en tres operaciones separadas.

  1. Formato básico: los números deben ser números; las fechas deben ser válidas, etc. Por lo general, esta validación es gratuita: el marco web lo hará por usted al vincular el contenido del widget al modelo.
  2. Validación de widget único: la fecha debe estar en el pasado; un entero debe estar entre 1 y 100; customerId debe existir en la base de datos, etc. Esto pertenece a la capa de controlador en la mayoría de los casos, pero puede necesitar soporte del repositorio de datos.
  3. Validación de widgets cruzados: la fecha de salida debe ser posterior a la fecha de entrada; la fecha de fallecimiento no puede ser anterior a la fecha de nacimiento, etc. Esta es definitivamente una validación de reglas de negocios. También tendemos a poner esto en la capa de controlador, pero es posible que desee cambiarlo a un validador de negocios para que pueda reutilizarse.

Si la capa 1 falla, no verificamos 2 o 3. De manera similar, si 1 tiene éxito y 2 falla, no hacemos 3. Esto detiene la generación de mensajes de error espurios.

Está preguntando acerca de los valores en una llamada REST en lugar de los contenidos del widget, pero se aplican los mismos principios.

kiwiron
fuente
-1

Enfoque de prueba conducido a la luz sobre esto, después de todo no hay controlador y debe elegir otra opción. Obviamente, las reglas de negocio deben estar en un solo lugar, y esta es otra restricción en su decisión.

Hans Poo
fuente