Tema representativo de entrevista

Entrevista de backend: diseñar una API de actualización condicional basada en ETag

BackendIntermedio
Equipo editorial de Offer.ccPublicado Actualizado

Pregunta

Múltiples clientes leen y actualizan el mismo recurso. Diseñe una API de actualización condicional basada en ETag que evite sobreescrituras obsoletas y explique la validación de caché, las respuestas de conflicto y los reintentos del cliente.

Planteamiento y alcance

Esta pregunta evalúa si un ingeniero de backend puede situar el control de concurrencia en el límite de HTTP. Explique la diferencia entre la validación de caché y la protección contra escritura, cómo compara el servidor las etiquetas de entidad, qué códigos de estado devuelve y cómo se mantienen alineadas las escrituras en la base de datos con los encabezados de respuesta.

Lo que evalúa el entrevistador

  • Si comprende los diferentes significados de ETag, If-Match e If-None-Match.
  • Si un validador fuerte protege las escrituras frente a versiones obsoletas.
  • Si 412, 428 y 409 tienen límites claros entre precondiciones y conflictos de negocio.
  • Si toma en cuenta las cachés proxy, los reintentos, la autorización y la visibilidad de las réplicas.

Preguntas aclaratorias para hacer primero

Confirme si las actualizaciones reemplazan el recurso completo o solo campos específicos, si los clientes deben enviar obligatoriamente una versión, si se admite la edición y fusión fuera de línea, si el ETag representa la representación completa o una versión de negocio, y si las lecturas y escrituras pasan a través de cachés, balanceadores de carga o múltiples réplicas de la base de datos.

Estructura para una respuesta de 30 segundos

Devuelva un ETag con cada representación del recurso. Exija If-Match en las mutaciones, compárelo con la versión actual dentro del límite de escritura y devuelva 412 en caso de discrepancia o 428 cuando falte una precondición obligatoria. En caso de éxito, incremente la versión y devuelva un nuevo ETag. Un GET con If-None-Match puede devolver 304, pero la validación de caché no protege las escrituras.

Respuesta a profundidad

1. Separar la validación de caché de la protección contra escritura

If-None-Match es útil para la validación de caché en solicitudes GET: una representación sin cambios puede producir un 304. If-Match exige que la representación actual coincida y es habitual en PUT, PATCH o DELETE. Un acierto de caché (cache hit) no otorga permiso para sobreescribir el recurso actual; la dirección de la comparación y el comportamiento ante fallos son diferentes.

2. Elegir un ETag seguro de comparar

Utilice un ETag fuerte para la protección contra escritura, de modo que los bytes o la versión definida coincidan con exactitud. Los ETag débiles son adecuados para representaciones en caché semánticamente equivalentes y no deben utilizarse para autorizar actualizaciones precisas. La etiqueta no debe exponer una secuencia interna ni datos sensibles; derívela a partir de una representación canónica y una versión con un salt impredecible, tras aplicar el filtrado por autorización.

3. Mantener la comparación y la actualización dentro de un mismo límite

Lea la versión actual, compare If-Match y actualice en una sola escritura condicional en la base de datos como UPDATE ... WHERE id = ? AND version = ?. Cero filas afectadas significa un 412; una actualización exitosa incrementa la versión y genera el nuevo ETag. No consulte en el código de la aplicación para luego emitir una escritura incondicional.

4. Diseñar respuestas de fallo y rutas de reintento

Devuelva 428 cuando falte una precondición obligatoria, 412 cuando el ETag no coincida y 409 para un conflicto independiente con el estado de negocio. Incluya la representación actual o una sugerencia para volver a consultar, pero no sobreescriba silenciosamente en nombre del cliente. Tras un 412, el cliente debe realizar un nuevo GET, mostrar una diferencia (diff) o aplicar una fusión de campos explícita y reintentar con el nuevo ETag; los reintentos automáticos requieren un número delimitado de intentos e idempotencia clara.

5. Gestionar cachés, réplicas y operaciones

La lectura que genera un ETag debe ver la última escritura, o el sistema debe definir un retraso de lectura tras escritura (read-after-write) delimitado. Los proxies deben reenviar correctamente ETag, If-Match e If-None-Match, con controles de caché adecuados para recursos sensibles. Registre en logs el ID de la solicitud, las versiones anterior y nueva, el resultado y la tasa de conflictos para identificar clientes que utilicen representaciones obsoletas o réplicas rezagadas.

Ejemplo de una respuesta sólida

Devolvería un ETag fuerte con cada GET, derivado de una representación canónica y de la versión. PUT, PATCH y DELETE requieren If-Match; la base de datos realiza una actualización condicional por versión, devolviendo 412 cuando ninguna fila coincide. Las precondiciones faltantes siguen la política de la interfaz y devuelven 428, mientras que el éxito incrementa la versión y devuelve el nuevo ETag. Un GET con un If-None-Match coincidente devuelve 304 únicamente para ahorro de caché. Tras un 412, el cliente vuelve a leer, muestra una diferencia o realiza una fusión explícita de campos, y reintenta con la nueva etiqueta. Las lecturas entre réplicas deben ver la versión actual, y los proxies deben reenviar los encabezados condicionales. Monitoree los conflictos, las solicitudes con versiones obsoletas y el retraso de las réplicas.

Errores comunes

  • Comparar solo las marcas de tiempo del cliente e ignorar el desfase del reloj (clock skew) o las diferencias de representación.
  • Usar un ETag débil para autorizar una escritura exacta.
  • Consultar primero la versión y luego escribir sin condiciones, dejando lugar a una condición de carrera.
  • Tratar 412, 409 y 428 como un único error genérico que no ofrece ningún paso siguiente al cliente.
  • Permitir que el servidor sobreescriba silenciosamente un conflicto y pierda la edición del cliente.
  • Generar etiquetas solo en los nodos de la aplicación sin considerar la visibilidad de la caché y de las réplicas.

Preguntas de seguimiento

¿Puede un ETag ser una versión autoincrementable de la base de datos?

Puede ser una entrada interna, pero codifique el valor para HTTP y evite exponer información comercial sensible. Si la representación cambia con el filtrado de campos o la autorización, genere la etiqueta en ese límite de la representación.

¿Se pueden fusionar automáticamente dos campos de PATCH que no se solapan?

Ofrezca un protocolo explícito de fusión a nivel de campo, pero continúe validando qué ETag utilizó el cliente. Publique reglas de fusión y no fusión y audite la decisión; que los campos sean diferentes no hace seguro ignorar todo conflicto de negocio.

¿Por qué no devolver simplemente 409?

412 significa que falló una precondición al estilo de If-Match, 428 le solicita al cliente que proporcione una, y 409 describe un conflicto independiente con el estado actual del recurso o una operación de negocio. La distinción le indica al cliente si debe volver a consultar los datos, añadir un encabezado o cambiar la acción.

¿Cómo se evitan las escrituras obsoletas a través de una CDN?

Enrute las mutaciones al origen autoritativo y utilice las cachés para las lecturas. Reenvíe los encabezados condicionales según la especificación, invalide las entradas afectadas tras una actualización exitosa o delimite la obsolescencia, y supervise las diferencias entre la versión del origen y la etiqueta en el borde (edge).

Fuentes públicas

Preguntas relacionadas