So I have been down the rabbit hole of finding that HTML forms don't support DELETE requests, and then looking into mimicking the the behaviour with a Javascript fetch request (but it is not straightforward to implement in Javascript). The way I see it, with or without Javascript, there are 3 options available:
Have a dedicated path for deleting resources For example
POST /resources/delete/resource_id
. This seems like the best option as it means you can have a dedicated route on the server. It is important to only accept POST requests so that users cannot accidentally delete a resource just by navigating to a URL.Adding a flag to the request data The same route is used for both posting and deleting, e.g.
POST /resources/resource_id
except that a flag is added to the request's data to signify whether it should be handled as a POST or DELETE. For example<input type="hidden" name="delete" />
. This seems to be a common approach, and feels nice because it uses the same path that an actual delete request would, e.gDELETE /resources/resource_id
. The major drawback is that if the flag is accidentally added to the request data, this would unintentionally change a POST request to a DELETE request, which is obviously very bad.Use Javascript to send an actual DELETE request This is nice because the server doesn't have to do anything different and can simply have a proper DELETE route like
DELETE /resources/resource_id
. This obviously makes sense if your webpage is a SPA which is already using Javascript to handle making network requests and page navigation. The downside is it is the most complex solution to implement. Also anytime you start using Javascript to mimic browser behaviour, you risk introducing different, unexpected behaviours. Below is my current best attempt which seems to work except clicking the back button to navigate to the previous page, the address bar updates but a request is not made by the browser and the previous HTML page is not rendered. Has anyone attempted something similar? Am I on the right track or is this a lost cause?
Currently my view is that option 1 is the best (easiest, most reliable and pragmatic) solution, but I am new to this and have struggled to find good resources on the web, should I would really appreciate some advice and guidance. What is common practice? What is best practice? Have I missed any other solutions? Using option 1, what form should the path take? /delete/resources/resource_id
, /resources/resource_id/delete
, etc.
<!DOCTYPE html>
<html lang="en">
<head>
<script>
window.onload = () => {
// find all forms with hidden value=delete input
const forms = document.querySelectorAll("form");
forms.forEach(form => {
const input = form.querySelector("input");
if (input.value == "delete") {
form.addEventListener("submit", async e => {
e.preventDefault();
const response = await fetch(form.action, {
body: new URLSearchParams(new FormData(e.currentTarget)),
method: "DELETE",
redirect: "follow",
});
const text = await response.text();
history.pushState({}, "", response.url);
window.document.body.innerHTML = text;
});
}
});
};
</script>
</head>
<body>
<form action="/delete" method="POST">
<input type="hidden" value="delete" />
<input type="submit" value="submit" />
<input name="key" value="val" />
</form>
</body>
</html>