HTTP DELETE Method: Complete Guide (2026)
Everything you need to know about the HTTP DELETE method for REST APIs
Start Building with Hypereal
Access Kling, Flux, Sora, Veo & more through a single API. Free credits to start, scale to millions.
No credit card required • 100k+ developers • Enterprise ready
HTTP DELETE Method: Complete Guide (2026)
The HTTP DELETE method removes a resource from the server. It is one of the four core HTTP methods used in RESTful APIs (alongside GET, POST, and PUT), and understanding how to use it correctly is essential for any developer working with APIs.
This guide covers the DELETE method in detail: how it works, when to use it, how to implement it on the client and server side, and common mistakes to avoid.
What Is the HTTP DELETE Method?
The DELETE method requests that the server remove the resource identified by the given URI. A successful DELETE operation means the resource no longer exists at that location.
DELETE /api/v1/users/42 HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
The server responds with a status code indicating the result:
HTTP/1.1 204 No Content
Key Characteristics
| Property | Value | Explanation |
|---|---|---|
| Request body | Optional (usually empty) | Most implementations ignore the body |
| Response body | Optional | 204 has no body; 200 may include details |
| Idempotent | Yes | Deleting the same resource twice yields the same result |
| Safe | No | It modifies server state |
| Cacheable | No | Responses should not be cached |
DELETE Response Status Codes
| Status Code | Meaning | When to Use |
|---|---|---|
| 200 OK | Resource deleted; response includes details | When you return a confirmation body |
| 202 Accepted | Deletion queued for processing | For async deletion (e.g., background jobs) |
| 204 No Content | Resource deleted; no response body | Most common response for DELETE |
| 404 Not Found | Resource does not exist | If the resource was never created |
| 401 Unauthorized | Authentication required | Missing or invalid credentials |
| 403 Forbidden | Authenticated but not authorized | User lacks delete permission |
| 409 Conflict | Cannot delete due to current state | E.g., resource has dependent records |
Choosing Between 200 and 204
# 204 No Content -- most common, no response body
DELETE /api/v1/users/42
Response: 204 No Content
# 200 OK -- when you want to return the deleted resource
DELETE /api/v1/users/42
Response: 200 OK
Body: {"id": 42, "name": "John", "deleted": true, "deletedAt": "2026-02-06T12:00:00Z"}
Use 204 when the client does not need confirmation details. Use 200 when the client benefits from seeing the deleted resource (e.g., for undo functionality or audit logs).
DELETE in Practice: Client-Side Examples
cURL
# Simple DELETE request
curl -X DELETE https://api.example.com/v1/users/42
# DELETE with authentication
curl -X DELETE \
-H "Authorization: Bearer your_token_here" \
https://api.example.com/v1/users/42
# DELETE with API key
curl -X DELETE \
-H "X-API-Key: your_api_key" \
https://api.example.com/v1/users/42
JavaScript (Fetch API)
// Basic DELETE request
const response = await fetch("https://api.example.com/v1/users/42", {
method: "DELETE",
headers: {
"Authorization": "Bearer your_token_here",
},
});
if (response.status === 204) {
console.log("User deleted successfully");
} else if (response.status === 404) {
console.log("User not found");
}
JavaScript (Axios)
import axios from "axios";
try {
await axios.delete("https://api.example.com/v1/users/42", {
headers: {
"Authorization": "Bearer your_token_here",
},
});
console.log("Deleted successfully");
} catch (error) {
if (error.response?.status === 404) {
console.log("User not found");
} else if (error.response?.status === 403) {
console.log("Not authorized to delete this user");
}
}
Python (requests)
import requests
response = requests.delete(
"https://api.example.com/v1/users/42",
headers={"Authorization": "Bearer your_token_here"}
)
if response.status_code == 204:
print("Deleted successfully")
elif response.status_code == 404:
print("User not found")
elif response.status_code == 409:
print("Cannot delete: user has dependent records")
Go
package main
import (
"fmt"
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.example.com/v1/users/42", nil)
req.Header.Set("Authorization", "Bearer your_token_here")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
switch resp.StatusCode {
case 204:
fmt.Println("Deleted successfully")
case 404:
fmt.Println("User not found")
case 403:
fmt.Println("Not authorized")
}
}
DELETE in Practice: Server-Side Examples
Node.js (Express)
import express from "express";
const app = express();
app.delete("/api/v1/users/:id", async (req, res) => {
const { id } = req.params;
// Check if user exists
const user = await db.users.findById(id);
if (!user) {
return res.status(404).json({ error: "User not found" });
}
// Check for dependent records
const orders = await db.orders.countByUserId(id);
if (orders > 0) {
return res.status(409).json({
error: "Cannot delete user with active orders",
orderCount: orders,
});
}
// Delete the user
await db.users.deleteById(id);
// Return 204 No Content
res.status(204).send();
});
Python (FastAPI)
from fastapi import FastAPI, HTTPException
app = FastAPI()
@app.delete("/api/v1/users/{user_id}", status_code=204)
async def delete_user(user_id: int):
user = await db.users.find_by_id(user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
if await db.orders.count_by_user_id(user_id) > 0:
raise HTTPException(
status_code=409,
detail="Cannot delete user with active orders"
)
await db.users.delete_by_id(user_id)
# FastAPI returns 204 automatically with no body
Go (net/http)
func deleteUserHandler(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
user, err := db.FindUserByID(id)
if err != nil || user == nil {
http.Error(w, "User not found", http.StatusNotFound)
return
}
if err := db.DeleteUser(id); err != nil {
http.Error(w, "Failed to delete user", http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusNoContent)
}
Idempotency: Why It Matters
The DELETE method is idempotent, meaning that making the same DELETE request multiple times produces the same result: the resource ends up deleted (or non-existent).
DELETE /api/v1/users/42 -> 204 No Content (user deleted)
DELETE /api/v1/users/42 -> 204 No Content (already deleted, same outcome)
However, there is a nuance. Some APIs return 404 on the second request because the resource no longer exists. Both approaches are valid:
| Approach | First Request | Second Request | Strictly Idempotent? |
|---|---|---|---|
| Always 204 | 204 | 204 | Yes |
| 404 if gone | 204 | 404 | Technically yes (resource is still deleted) |
The "always 204" approach is simpler for clients because they do not need to distinguish between "just deleted" and "already deleted."
Soft Delete vs Hard Delete
In production systems, many teams implement soft delete instead of actually removing data:
Hard Delete
-- Data is permanently removed
DELETE FROM users WHERE id = 42;
Soft Delete
-- Data is marked as deleted but retained
UPDATE users SET deleted_at = NOW(), is_active = false WHERE id = 42;
| Approach | Recoverable | Storage | Compliance | Complexity |
|---|---|---|---|---|
| Hard delete | No | Saves space | GDPR-friendly | Simple |
| Soft delete | Yes | Grows over time | Needs purge job | Moderate |
The API endpoint looks the same to the client (DELETE /api/v1/users/42). The difference is in the server-side implementation.
Bulk Delete
Sometimes you need to delete multiple resources at once. There are two common patterns:
Pattern 1: Query Parameters
DELETE /api/v1/users?ids=1,2,3,4,5
Pattern 2: Request Body
curl -X DELETE https://api.example.com/v1/users \
-H "Content-Type: application/json" \
-d '{"ids": [1, 2, 3, 4, 5]}'
Pattern 3: POST to a Delete Endpoint
Some APIs avoid sending a body with DELETE and use POST instead:
POST /api/v1/users/bulk-delete
Body: {"ids": [1, 2, 3, 4, 5]}
Pattern 3 is the most widely compatible because some HTTP clients and proxies strip the body from DELETE requests.
Common Mistakes
1. Not Checking Authorization
Always verify the caller has permission to delete the resource:
app.delete("/api/v1/posts/:id", async (req, res) => {
const post = await db.posts.findById(req.params.id);
if (post.authorId !== req.user.id && !req.user.isAdmin) {
return res.status(403).json({ error: "Not authorized" });
}
// ... proceed with deletion
});
2. Not Handling Cascading Deletes
Deleting a parent resource can orphan child records. Handle this explicitly:
// Delete user and all related data
await db.transaction(async (tx) => {
await tx.comments.deleteByUserId(userId);
await tx.posts.deleteByUserId(userId);
await tx.sessions.deleteByUserId(userId);
await tx.users.deleteById(userId);
});
3. No Confirmation for Destructive Actions
For critical resources, consider requiring a confirmation parameter:
DELETE /api/v1/projects/42?confirm=true
Conclusion
The HTTP DELETE method is straightforward in concept but requires careful implementation. Always authenticate and authorize requests, handle edge cases (missing resources, dependent records), and decide between soft and hard deletes based on your data retention requirements.
If you are building applications that interact with media generation APIs, Hypereal AI provides a clean REST API where you might use DELETE to manage generated assets, remove uploaded images, or clean up completed video generation jobs.
Related Articles
Start Building Today
Get 35 free credits on signup. No credit card required. Generate your first image in under 5 minutes.
