Planteamiento y contexto
Una API sirve un documento con un validador de versión. Múltiples clientes pueden leerlo y editarlo de forma concurrente, y el requisito es rechazar escrituras desactualizadas manteniendo la API reintentable y observable.
Qué evalúa el entrevistador
- Distinguir el almacenamiento en caché de representaciones frente a las precondiciones de escritura.
- Elegir un ETag fuerte y exigir
If-Matchen los métodos de mutación. - Devolver 412 ante una versión desactualizada y definir una ruta segura de recuperación para el cliente.
Preguntas aclaratorias antes de responder
- ¿El ETag representa la representación exacta almacenada o solo una versión semántica débil?
- ¿Qué métodos requieren una precondición: PUT, PATCH, DELETE o todas las escrituras?
- ¿Debería un cliente fusionar campos automáticamente o debe un humano resolver los conflictos?
- ¿Los reintentos se envían a través de una API con balanceo de carga y un único almacén de datos transaccional?
Estructura de respuesta de 30 segundos
Devolvería un ETag fuerte con cada representación editable. El cliente envía ese valor en If-Match en peticiones PUT, PATCH o DELETE. El servidor lo compara dentro de la misma transacción que la actualización; una discrepancia devuelve 412 sin aplicar la mutación. La respuesta debe incluir la representación actual o una señal de recarga, mientras que las métricas rastrean los conflictos y las precondiciones ausentes. Luego, el cliente vuelve a obtener el recurso, fusiona deliberadamente y reintenta con el nuevo ETag.
Análisis detallado paso a paso
1. Emitir un validador
En GET, devuelva el documento y un ETag derivado de la versión canónica almacenada. Un número de revisión de la base de datos puede ser más simple que generar el hash de una carga útil grande, siempre que el valor cambie cada vez que cambie la representación relevante para la edición. Use un validador fuerte para If-Match; los validadores débiles no son adecuados para proteger el estado exacto de escritura.
2. Hacer cumplir la precondición de forma atómica
La actualización debe verificar la versión esperada y escribir la nueva versión como una única operación condicional. Conceptualmente:
UPDATE documents
SET body = :new_body, version = version + 1
WHERE id = :id AND version = :expected_version;Si el conteo de filas afectadas es cero, devuelva 412 y no ejecute ningún efecto secundario. Verificar el ETag en la memoria de la aplicación y escribir después crea una condición de carrera entre la verificación y el commit.
3. Separar el 412 de otros fallos
412 significa que la precondición proporcionada es falsa; es un conflicto de concurrencia, no un JSON mal formado ni un fallo de autenticación. Devuelva 400 para una estructura de solicitud no válida, 401 o 403 para autorización y 404 cuando el recurso no esté disponible según la política de la API. Esta distinción permite que los clientes elijan entre recargar y fusionar frente a una corrección manual del usuario.
4. Diseñar la recuperación del cliente
Tras un 412, obtenga el documento actual y muestre los campos en conflicto o un diff. Una fusión automática es segura solo cuando la semántica a nivel de campo y las reglas de autorización lo hacen seguro. El reintento debe utilizar el nuevo ETag devuelto y permanecer idempotente a nivel de recurso; nunca reenvíe a ciegas la solicitud desactualizada.
5. Mantener la coherencia de cachés y réplicas
Genere validadores a partir del estado confirmado visible para la ruta de escritura. Una lectura de una réplica rezagada puede devolver un ETag antiguo y provocar conflictos evitables, mientras que una escritura enrutada a otro nodo aún debe hacer cumplir la versión en la transacción primaria. Emita métricas de tasa de conflictos, tasa de If-Match faltante y tasa de éxito de reintentos.
Respuesta de ejemplo de alta calidad
“Devolvería un ETag fuerte para cada documento editable y exigiría If-Match en las mutaciones. El servidor compararía la etiqueta en la misma transacción que actualiza la fila, mediante una actualización de versión condicional. Si ninguna fila coincide, devuelve 412 y no aplica efectos secundarios. El cliente vuelve a obtener el recurso, presenta un diff o realiza una fusión estrictamente definida, y luego reintenta con el nuevo ETag. Distinguiría el 412 de los errores de validación y autorización, y monitorearía las tasas de lecturas desactualizadas, conflictos y éxito de reintentos.”
Errores comunes
- Verificar el ETag y luego actualizar en operaciones separadas → persiste una condición de carrera → ejecute el predicado de versión y la escritura de forma atómica.
- Usar un validador débil para escrituras exactas → el contenido semánticamente similar puede compararse incorrectamente → use un validador fuerte.
- Devolver 409 para cada escritura desactualizada → los clientes no pueden distinguir las precondiciones del protocolo → use 412 para una condición
If-Matchfallida. - Reintentar a ciegas la carga útil desactualizada → los cambios del primer editor pueden perderse → vuelva a obtener el recurso, fusione intencionalmente y reintente con la nueva etiqueta.
Preguntas de seguimiento y respuestas
¿Sirve ETag solo para almacenamiento en caché?
No. If-None-Match habitualmente habilita la validación de caché, mientras que If-Match hace que una escritura sea condicional a la representación actual. El mismo validador puede cumplir ambas funciones si su fuerza de comparación y su política de generación son correctas.
¿Qué ocurre si el cliente omite If-Match?
Para recursos que requieren concurrencia optimista, rechace la mutación con una respuesta documentada de precondición requerida o una política 400 clara. Aceptar silenciosamente una escritura no condicionada reintroduce las actualizaciones perdidas; la política debe ser consistente en todos los métodos.
¿Debería el servidor devolver el documento más reciente en una respuesta 412?
Puede hacerlo, si la autorización y el tamaño de la carga útil lo permiten, pero el contrato aún debe requerir una nueva obtención o una resolución explícita de conflictos. Devolver datos no autoriza al cliente a sobrescribirlos sin utilizar el validador más reciente.