with restresource pageable example data custom spring rest spring-boot spring-data spring-data-rest

restresource - Con Spring Data REST, ¿por qué la propiedad @Version se está convirtiendo en ETag y no está incluida en la representación?



spring data rest example (1)

En Spring Data REST (a través de Spring Boot 1.3.3), cuando GET una colección de recursos de, por ejemplo, people , la propiedad @Version no se incluye con los recursos:

$curl -v http://localhost:8080/api/people/1 * Trying ::1... * Connected to localhost (::1) port 8080 (#0) > GET /api/people/1 HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.42.1 > Accept: */* > < HTTP/1.1 200 OK < Server: Apache-Coyote/1.1 < ETag: "0" < Last-Modified: Tue, 26 Apr 2016 00:08:12 GMT < Content-Type: application/hal+json;charset=UTF-8 < Transfer-Encoding: chunked < Date: Tue, 26 Apr 2016 00:12:56 GMT < { "id" : 1, "createdDate" : { "nano" : 351000000, "epochSecond" : 1461629292 }, "lastModifiedDate" : { "nano" : 351000000, "epochSecond" : 1461629292 }, "firstName" : "Bilbo", "lastName" : "Baggins", "_links" : { "self" : { "href" : "http://localhost:8080/api/people/1" }, "person" : { "href" : "http://localhost:8080/api/people/1" } } * Connection #0 to host localhost left intact

de forma predeterminada, o cuando configuro mi repositorio de Spring Data:

@Configuration public class ApplicationRepositoryConfiguration extends RepositoryRestMvcConfiguration { @Override protected void configureRepositoryRestConfiguration( RepositoryRestConfiguration config ) { config.exposeIdsFor(Person.class); config.setBasePath("/api/"); } }

La versión @Version es la versión de la fila de datos que se incrementa en las actualizaciones y se incluye en los datos del encabezado HTTP ETag cuando consulto un recurso específico. En lugar de tener que invocar un GET en cada recurso de la colección, preferiría obtener @Version en la colección GET para que pueda escribir mi aplicación para verificar el valor de @Version en cada actualización de recursos sin realizar la suma adicional GET round- excursiones.

¿Hay alguna manera de incluir el campo @Version en cada uno de los recursos de una colección GET ?

La definición de entidad se ve así:

@Data @Entity @EntityListeners(AuditingEntityListener.class) public class Person { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; @CreatedDate @Column(nullable=false) private Instant createdDate; @LastModifiedDate @Column(nullable=false) private Instant lastModifiedDate; @Version @JsonProperty private Long version; … }


No no hay. El ETag es el HTTP equivalente a lo que se expresa como propiedad @Value en el back-end. Spring Data REST convierte todas las propiedades relacionadas con back-end que tienen un mecanismo correspondiente en el protocolo HTTP exactamente en esas: los identificadores se convierten en URI (y no deben formar parte de la carga útil), @LastModifiedDate propiedades @LastModifiedDate convierten en encabezados, @Version propiedades @Version convierten en ETags.

La razón es bastante simple: si usa HTTP, use los medios de protocolo que están disponibles para lograr cosas que se implementan en el nivel de acceso a datos. Ese es un aspecto en el que Spring Data REST no está simplemente exponiendo una base de datos a la web, sino que realmente inspecciona su modelo y traduce las características del modelo en medios específicos del protocolo.

Para resumir: con Spring Data REST tiene dos opciones para las actualizaciones:

  1. Simplemente PUT sin un encabezado If-Match : impone la anulación de todo lo que está presente en el servidor a medida que se carga el agregado, los datos entrantes se asignan y se escriben de nuevo. Aún se aplica el bloqueo optimista si otro cliente cambió el agregado mientras tanto (aunque es una ventana muy corta). Si ese es el caso, verás un 409 Conflict .
  2. PUT con un encabezado If-Match - Spring Data REST comprueba el ETag presentado contra el valor actual de la propiedad de versión del agregado y devuelve un 412 Precondition Failed en caso de que exista una discrepancia en ese punto. En ese caso, los clientes pueden buscar el estado actual del recurso y decidir cómo proceder. Podrían decidir anular lo que está en el servidor usando PUT sin un encabezado If-Match .

Se pueden realizar optimizaciones similares para las solicitudes GET:

  1. GET con If-None-Match (ETag) / If-Modified-Since (con el valor de encabezado Last-Modified) - Verá un 304 Not Modified en caso de que el recurso aún se encuentre en el mismo estado que antes y así evitará gastar ancho de banda para la respuesta.
  2. Plain GET siempre devolverá la representación.