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

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

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

[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
    if (!categoryDao.Delete(id))
    {
        return NotFound();
    }
    return NoContent();
}
DELETE {{HostAddress}}/api/categories/9
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:

DELETE {{HostAddress}}/api/categories/1
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

Cheat sheets