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.

Deleting a resource

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

Accessing deleted resources

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

Recover a soft deleted resource

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

Permanent deletion

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.

Filtering and rendering of archived resources

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:

  1. work (whereas they would normally return a 410 Gone)
  2. 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.

Historical notes

Why bother with soft deletes at all?

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.

Why bother with permanent deletes at all?

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.

Why don't we use DELETE on the resource as a permanent delete?

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.

Why use an actions convention for adding extra semantics?

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).

⚠️ **GitHub.com Fallback** ⚠️