# DELETE

DELETE removes the item at an address. It sends no body; the action deletes by the id from the route and answers 204 No Content, or 404 Not Found when there was nothing to delete.

Journeyman · ASP.NET Core · REST API · Updated November 3, 2026

## After this lesson you can

- Write a DELETE action that removes an item and answers 204 No Content, or 404 Not Found when it isn't there

## Key takeaways

- A `DELETE` to an item's address removes it. It sends no body: the id comes from the route.
- The DAO returns `rows == 1`, and the action answers `204 No Content`, or `404 Not Found` when there was nothing to delete.
- Deleting a category that still has products breaks a foreign key, and the uncaught `SqlException` sends the client a `500` with the stack trace.
- Errors like that are best handled once, for the whole API, not in each action.

A client **deletes** an item with a `DELETE` to that item's address. Like a `GET`, it has no body: the address says which item.

## The DAO

```csharp
public bool Delete(int categoryId)
{
    using SqlConnection connection = new SqlConnection(connectionString);
    int rows = connection.Execute("DELETE FROM Categories WHERE CategoryId = @CategoryId;", new { CategoryId = categoryId });
    return rows == 1;
}
```

Dapper's `Execute` returns how many rows the statement changed, so the number of rows tells you whether there was anything to delete. Unlike `Update`, there's nothing to hand back: the row is gone.

## The action

```csharp
[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
    if (!categoryDao.Delete(id))
    {
        return NotFound();
    }
    return NoContent();
}
```

```http
DELETE {{HostAddress}}/api/categories/9
```

```http
HTTP/1.1 204 No Content
```

Send the same request again, and it answers `404 Not Found`: category 9 is already gone.

## When the database says no

Now try deleting a category that has products:

```http
DELETE {{HostAddress}}/api/categories/1
```

```http
HTTP/1.1 500 Internal Server Error

Microsoft.Data.SqlClient.SqlException (0x80131904): The DELETE statement conflicted with the REFERENCE constraint "FK_Products_Categories". ...
```

Beverages has products, and the foreign key from *Database Design in SQL Server* won't let its category go. The DAO throws a `SqlException`, nobody catches it, and the client gets a `500` with the full error and stack trace.

That's fine while you develop: you see exactly what broke. But a real client should never see your stack trace, and a foreign-key conflict isn't really a server crash. *Handling Global Exceptions in ASP.NET Core* shows how to answer with something better, in one place for the whole API.

## The full controller

With `GET`, `POST`, `PUT` and `DELETE`, the categories API is complete: five endpoints, all CRUD, in one class.

| Request | Action | Answers |
|---|---|---|
| `GET /api/categories` | `GetAll()` | `200` with the list |
| `GET /api/categories/8` | `GetById(8)` | `200` with the category |
| `POST /api/categories` | `Add(category)` | `201` with the new category and its address |
| `PUT /api/categories/8` | `Update(8, category)` | `200` with the updated category, or `404` |
| `DELETE /api/categories/8` | `Delete(8)` | `204`, or `404` |

## Check yourself

1 question to try on the lesson page.

## So what

DELETE is the simplest action: an id in, a status out. The interesting part is what happens when the database refuses, and that's a job for the whole API, not one action.

## Key terms

- [DELETE (HTTP)](https://www.ask-codey.com/glossary/delete-http)

## Cheat sheets

- [PUT and DELETE](https://www.ask-codey.com/cheat-sheets/web-apis-with-controllers-put-cheat-sheet)

Source: https://www.ask-codey.com/lessons/web-apis-with-controllers-delete
