API: Archiving - QutEcoacoustics/baw-server GitHub Wiki
We've long supported soft deletes (archiving of resources by default).
This is typically done by setting a column that indicates the archived status (by convention the column is named deleted_at
) to a non-null timestamp.
Those records are automatically removed from most queries.
Historically, issuing DELETE
twice to a resource would really delete it.
However, this never really worked.
Recently we've added default support to routes that support soft deletes. The behavior of those routes is as follows.
Issuing a DELETE
on a resource will either permanently delete it or soft delete it.
Request:
DELETE /projects/1
Response:
204 No Content
If the resource supports soft deletes the resource will additionally return a header indicating its archived status.
Response:
204 No Content
X-Archived-At: Tue, 27 Aug 2024 04:58:22 GMT
Truly deleted resources will return a 404 Not Found
response. However archived resources will return a 410 Gone
response.
For example, given any of the following requests to a soft deleted resource:
GET /projects/1
PUT /projects/1 # <snip body content>
DELETE /projects/1
POST /projects/1/restart # an "action"
The expected response would be:
410 Gone
X-Archived-At: Tue, 27 Aug 2024 04:58:22 GMT
We use our API: Actions conventions to add extra semantics to our resource.
To recover a deleted resource:
POST /projects/1/recover
And you can expect an actions conforming response:
204 No Content
Location: /projects/1
Cache-Control: no-cache
We use our API: Actions conventions to add extra semantics to our resource.
To permanently delete a resource issue a request such as:
DELETE /projects/1/destroy
POST
is also an acceptable verb:
POST /projects/1/destroy
The response will not include an archived header:
204 No Content
A permanent delete request will work if a whether or not a resource is archived.
Archived resources may be included in all normal actions if the with_archived
query string parameter is included.
For example, given an archived resource, the following requests will either:
- work (whereas they would normally return a
410 Gone
) - or include archived resources in the listing (whereas they would normally be omitted)
GET /projects?with_archived
GET /projects/1?with_archived
PUT /projects/1?with_archived # <snip body>
POST /projects/1/restart?with_archived
POST /projects/filter?with_archvied
Note: the with_archived
QSP may trigger its own authorization logic. In the most common case only the admin
role will have access to this functionality.
We want our default and common API calls to be safe by default. True deletion leads to cascading entity deletion in the database and should be exceedingly rare. It must be very well tested to be considered supported.
Sometimes true deletion is needed, usually as a task an admin has to do. Before this common functionality was implemented, permanent deletion had to be achieved via the dev console on production servers. This not safe, and not tested. In short admin is a user and admin tasks are features too.
Backwards compatibility. For the entirety of our API's existence, issuing a DELETE
on a resource would soft delete if the resource supported soft deletes. Changing that behavior now would be an unacceptable breaking change.
We can also apply different permissions (like admin only access) to permanent deletion actions because it is easy to route to different controller actions.
The so called "double-tap" method (issuing two DELETE
requests to the same resource) is no more semantically correct (in terms of best standard REST practices) than our actions convention. It is also harder to document, overloaded with complexity, and not idempotent (idempotency on a delete is not expected, but it is a nice property for resources that support archiving).