Recuperar RESTful
http http-delete (4)
Creo que la forma más RESTANTE de resolver esto es usar HTTP PUT para marcar el recurso para su eliminación (y recuperar) y luego usar HTTP DELETE para eliminar el recurso de forma permanente. Para obtener una lista de los recursos marcados para su eliminación, usaría un parámetro en la solicitud HTTP GET, por ejemplo. ?state=markedForDeletion
. Si solicita un recurso marcado para eliminación sin el parámetro, creo que debe devolver el estado "404 No encontrado".
Es un requisito bastante común para admitir undeletes o eliminaciones retrasadas / por lotes para servicios de datos. Lo que me pregunto es cómo implementar esto de una manera RESTANTE. Estoy dividido entre algunas opciones diferentes (ninguna de las cuales me parece terriblemente atractiva). Común a través de estas diferentes opciones, creo, es la necesidad de una API que devuelva todos los recursos marcados como eliminados para un tipo de recurso en particular.
Aquí hay algunas opciones que he pensado y algunos de sus pros / contras:
Opciones para marcar el recurso como eliminado:
- Use HTTP DELETE para marcar el recurso como eliminado.
- Use HTTP PUT / POST para actualizar el indicador borrado. Esto no parece correcto ya que mapea lo que es esencialmente una eliminación del método DELETE HTTP y en otros métodos HTTP.
Opciones cuando GET-ing recurso marcado para eliminación:
- Devuelve HTTP Status 404 para un recurso marcado como eliminado. Limpio y transparente, pero ¿cómo podemos decir la diferencia entre un recurso que realmente se borró frente a uno que acaba de marcar como eliminado?
- Devuelve el estado HTTP 410. Proporciona una forma de ver la diferencia, pero técnicamente 410 dice que "se espera que se considere permanente. Los clientes con capacidades de edición de enlaces DEBERÍAN eliminar las referencias al URI de solicitud después de la aprobación del usuario". Puede haber suficiente margen de maniobra en las palabras "esperado" y "DEBERÍA" aquí. No estoy seguro de qué tan bien 410 está soportado / entendido por los clientes.
- Regrese al estado HTTP 200 e incluya el campo indicador que indica que el recurso ha sido eliminado. Esto parece extraño, ya que la idea de eliminarlo en primer lugar era porque realmente quería que no apareciera. Esto aumenta la responsabilidad de filtrar los recursos eliminados a los clientes.
Opciones para respuestas que incluyen este recurso eliminado:
- Omita los recursos procesados como eliminados. Limpio y simple. Pero, ¿qué sucede si realmente quiere saber sobre los recursos eliminados?
- Inclúyalos junto con el campo que indica que están eliminados. Esto aumenta la responsabilidad de filtrar los recursos eliminados a los clientes. Hace que la paginación sea difícil si solo desea navegar por los recursos activos o eliminados.
Opciones al actualizar un recurso marcado para eliminación:
- Use HTTP Status 404. El recurso se ha ido ¿verdad? Pero, ¿cómo se puede diferenciar entre un recurso marcado como eliminado y uno realmente eliminado? El cuerpo HTTP en la respuesta 404 podría desambiguar aquí, pero a los clientes les quedará analizar / interpretar su cuerpo para desambiguar. Tal vez el encabezado de respuesta podría ayudar aquí? ¿Cúal? ¿Cabecera personalizada?
- Use el estado HTTP 409 con un mensaje sobre cómo el recurso debe ser recuperado por primera vez.
Opciones para recuperar el recurso marcado para eliminación:
- Use HTTP PUT / POST para actualizar la operación del recurso y márquelo como activo nuevamente. Esto solo funciona siempre y cuando no devuelva un HTTP 404 para la operación GET para el recurso, ya que no lo hace desde PUT / POST a un recurso que es "No encontrado" (404).
- Use HTTP PUT / POST para la operación de creación del recurso. El problema aquí es, ¿qué datos tienen prioridad? ¿Los datos enviados en la operación de creación? O los datos que se están recuperando? filtrarlo de cualquier otra consulta que lo haya devuelto. A continuación, trate el HTTP PUT / POST que crea el recurso como un recuperar si el identificador de recursos apunta a un recurso marcado como eliminado.
- Ruta de REST separada dedicada a recuperar los recursos marcados para su eliminación.
Esto de ninguna manera es una lista exhaustiva. Solo quería enumerar algunas de las opciones que han estado rebotando en mi cabeza.
Sé que la respuesta a cómo hacer esto es, como de costumbre, "depende". Lo que me interesa es saber qué requisitos / requisitos usarías para tomar una decisión. ¿Cómo ha visto esto implementado o implementado usted mismo?
Los artículos "eliminados" (desechados) también se pueden considerar como un recurso, ¿no? Entonces podemos acceder a este recurso de una de estas maneras (por ejemplo, para un usuario eliminado):
PATCH deleted_users/{id}
PATCH trash/users/{id}
PATCH deleted/users/{id}
o algunas personas pueden pensar que esta es una forma más tranquila:
PATCH deleted/{id}?type=users
y en payload dice algo como esto:
{ deleted_at: null }
Pasando por el libro: RFC 2616-9.7 :
The DELETE method requests that the origin server delete the resource
identified by the Request-URI. This method MAY be overridden by human
intervention (or other means) on the origin server. The client cannot
be guaranteed that the operation has been carried out, even if the
status code returned from the origin server indicates that the action
has been completed successfully. However, the server SHOULD NOT
indicate success unless, at the time the response is given, if it intends
to delete the resource or move it to an inaccessible location.
Cuando ELIMINA un recurso, el servidor debe marcar el recurso para su eliminación. En realidad, no tiene que eliminar el recurso, simplemente no puede dar ninguna garantía de que la operación se haya llevado a cabo. Aun así, el servidor no debe decir que se eliminó cuando no lo hizo.
A successful response SHOULD be 200 (OK) if the response includes an entity
describing the status, 202 (Accepted) if the action has not yet been enacted,
or 204 (No Content) if the action has been enacted but the response does not
include an entity.
Si la operación se retrasa, envíe un 202 y un cuerpo de entidad que describa el resultado de la acción. (Piense en una "tarea" poll-able que represente la eliminación diferida del recurso por parte del servidor; teóricamente podría dejarla para siempre en ese estado). Todo lo que tiene que hacer es evitar que el cliente la recupere nuevamente en su forma original. Use un 410 para el código de respuesta, y cuando la "tarea" finalice o el servidor elimine el recurso, devuelva un 404.
Sin embargo, si la semántica de un DELETE no tiene sentido para el recurso en cuestión, quizás no es una eliminación lo que está buscando, sino una transición de estado adicional que altera el estado del recurso pero lo mantiene accesible. En ese caso, use un PUT / PATCH para actualizar el recurso y listo.
La versión corta
No se puede recuperar RESTfully un recurso utilizando ningún método en su URI original; es ilógico, porque cualquier operación intentada en un recurso que se ha eliminado debe devolver un 404 o un 410. Si bien esto no se establece explícitamente en la especificación, está fuertemente implícito en la definición del método DELETE 1 (énfasis agregado):
En efecto, este método es similar al comando rm en UNIX: expresa una operación de eliminación en la asignación de URI del servidor de origen en lugar de una expectativa de que se borre la información previamente asociada.
En otras palabras, cuando ha ELIMINADO un recurso, el servidor ya no asigna ese URI a esa información. Por lo tanto, no puede PONERLO ni PUBLICARLO para realizar una actualización como "marcar esto como no recuperado", etc. (Recuerde que un recurso se define como un mapeo entre un URI y algunos datos subyacentes).
Algunas soluciones
Como se afirma explícitamente que los datos subyacentes no se eliminan necesariamente, no impide que el servidor realice una nueva asignación de URI como parte de la implementación DELETE, lo que hace que la copia de seguridad se pueda restaurar más adelante.
Podría tener una colección "/ deleted /" que contenga todos los elementos eliminados, pero ¿cómo realizaría realmente la recuperación? Quizás la forma RESTful más simple es hacer que el cliente recupere el elemento con GET, y luego POST a la URL deseada.
¿Qué sucede si necesita poder restaurar el elemento eliminado en su ubicación original? Si está utilizando un tipo de medio que lo admite, puede incluir el URI original en la respuesta a un GET de / deleted / collection. El cliente podría entonces usarlo para POST. Tal respuesta podría verse así en JSON:
{
"original-url":"/some/place/this/was/deleted/from",
"body":<base64 encoded body>
}
El cliente podría POSTAR ese cuerpo a ese URI para realizar una recuperación.
Alternativamente, si la definición de su recurso permite el concepto de movimiento (al actualizar una propiedad de "ubicación" o algo así), entonces puede hacer una actualización parcial y evitar el viaje de ida y vuelta del objeto completo. O bien, haga lo que hace la mayoría de las personas e implemente una operación similar a RPC para indicarle al servidor que mueva el recurso. INCORRECTO, sí, pero probablemente funcionará bien en la mayoría de las situaciones.
Cómo decides estas cosas
En cuanto a la cuestión de cómo decide estas cosas: debe considerar qué significa eliminar en el contexto de su aplicación, y por qué la quiere. En muchas aplicaciones, nunca se borra nada, y "eliminar" realmente significa "excluir este elemento de todas las demás consultas / listas, etc. a menos que lo recupere explícitamente". Entonces, realmente es solo una pieza de metadato, o una operación de movimiento. En ese caso, ¿por qué molestarse con HTTP DELETE? Una razón podría ser si desea una eliminación de 2 niveles: una versión suave o temporal que no se puede copiar, y una versión dura / permanente que es, bueno ... no.
En ausencia de un contexto de aplicación específico, me inclinaría a implementarlos así:
No quiero ver este recurso por más tiempo, para mi conveniencia : PUBLICAR una actualización parcial para marcar el recurso como "eliminado temporalmente"
No quiero que nadie pueda llegar a este recurso por más tiempo porque es embarazoso / incriminatorio / me cuesta dinero / etc : HTTP DELETE
La siguiente pregunta a considerar es: ¿debería la eliminación permanente solo desasignar el URI permanentemente, para que nadie pueda seguir vinculándolo o también para purgar los datos subyacentes? Obviamente, si conserva los datos, un administrador puede restaurar incluso un recurso eliminado "permanentemente" (no a través de ninguna interfaz RESTful). La desventaja de esto es que si el propietario de los datos realmente quiere que se purgue, un administrador tiene que hacer eso fuera de la interfaz REST.