Мягкое удаление (soft delete)
Сегодня хочу поделиться кратким пересказом главы из книги “API Design Patterns” Дж. Дж. Гивакса, посвящённой паттерну мягкое удаление (soft delete).
Мягкое удаление позволяет пометить ресурс удаленным, а не удалять его физически. Это полезно, когда необходимо предотвратить случайное удаление данных или скрыть ресурс на время, сохраняя возможность его восстановления.
Для реализации мягкого удаления нужно обогатить ресурс специальным полем, по которому можно будет понять помечен ли ресурс для удаления. Метод Delete будет менять состояние этого поля, а не удалять ресурс (причем Delete теперь больше похож на Update). Для восстановления ресурса используется метод Undelete. Окончательное удаление будет выполняться с помощью метода Expunge. Также, нужно обеспечить, чтобы ресурсы, помеченные как удалённые, не отображались в результатах метода List, но могли быть включены в список по запросу.
Важные моменты при реализации:
- Логический флаг vs поле status. Самый простой способ, использовать булевое поле, например,
is_deleted
, которое принимает значениеtrue
илиfalse
— это просто и понятно, но имеет ограничения в плане гибкости, особенно если нужно учитывать больше состояний. Более гибкий подход, когда ресурс имеет полеstatus
, которое может принимать разные значения:active
,deleted
,archived
— это позволяет управлять состоянием ресурса с учётом разных бизнес-требований, однако может вызвать сложности (например, какое состояние присвоить при восстановлении ресурса?). - Метод Delete (
DELETE /resources/{id}
) вместо удаления ресурса помечает его удалённым. При этом метод должен возвращать изменённый ресурс. Если попытаться удалить уже удалённый ресурс, лучше возвращать ошибку (например,412 Precondition Failed
) чтобы клиенты понимали, что ресурс уже был удален. - Метод Get (
GET /resources/{id}
) — для мягко удалённых ресурсов возвращает сам ресурс, а не ошибку404 Not Found
(когда нам известен идентификатор ресурса, его извлечение по нему скорее всего означает, что мы хотим узнать, был ли он мягко удален, а не то, что мы знаем о его удалении и все равно хотим просмотреть содержащиеся в нем данные). - Метод List (
GET /resources
) — нужно исключать удалённые ресурсы, но лучше предоставлять возможность их включения в ответ (например добавить параметр запросаincludeDeleted
). - Метод Undelete (
POST /resources/{id}:undelete
) нужен для восстановления мягко удаленных ресурсов, снимая с них отметку об удалении. - Метод Expunge (
POST /resources/{id}:expunge
) предназначен для окончательного удаления ресурса, независимо от того был ли он удален мягко или еще нет. - Срок хранения. Для мягко удалённых ресурсов можно указать срок хранения чтобы по истечении этого срока они удалялись физически (например через поле
expireTime
, которое устанавливается при удалении ресурса и сбрасывается при его восстановлении). - Ссылочная целостность. Мягкое удаление не должно нарушать ссылочную целостность (когда один ресурс ссылается на другой). То есть при мягком удалении, ссылки на него должны оставаться корректными.
#заметки_из_книг