Implementing CRUD (Create, Read, Update, Delete) operations is fundamental to building any Web API. These operations allow clients to interact with your data in a meaningful way. This lesson will guide you through implementing these operations in your ASP.NET Core Web API, building upon the foundation we established in the previous lessons. We'll focus on creating API endpoints that handle different HTTP methods (POST, GET, PUT, DELETE) and interact with a data source.
CRUD is an acronym that stands for Create, Read, Update, and Delete. These are the four basic operations that can be performed on data. In the context of Web APIs, each CRUD operation is typically mapped to a specific HTTP method:
POST HTTP method.GET HTTP method.PUT or PATCH HTTP method. PUT is generally used for complete replacement of a resource, while PATCH is used for partial updates. We'll focus on PUT in this lesson for simplicity.DELETE HTTP method.Let's assume you have a basic ASP.NET Core Web API project set up, as covered in the previous lesson. We'll continue with the "Books" example. If you don't have a project, create a new one using the ASP.NET Core Web API template in Visual Studio or VS Code.
First, let's define a simple Book model:
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public string Author { get; set; }
}
Next, we'll need a way to store and manage our books. For simplicity, we'll use an in-memory list. In a real-world application, you would typically use a database.
public class BookRepository
{
private static List<Book> _books = new List<Book>();
private static int _nextId = 1;
public List<Book> GetAll()
{
return _books;
}
public Book? GetById(int id)
{
return _books.FirstOrDefault(b => b.Id == id);
}
public Book Add(Book book)
{
book.Id = _nextId++;
_books.Add(book);
return book;
}
public void Update(Book book)
{
var existingBook = _books.FirstOrDefault(b => b.Id == book.Id);
if (existingBook != null)
{
existingBook.Title = book.Title;
existingBook.Author = book.Author;
}
}
public void Delete(int id)
{
var bookToRemove = _books.FirstOrDefault(b => b.Id == id);
if (bookToRemove != null)
{
_books.Remove(bookToRemove);
}
}
}
Now, let's create an API controller named BooksController to handle the CRUD operations.
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
private readonly BookRepository _bookRepository;
public BooksController()
{
_bookRepository = new BookRepository();
}
// GET: api/Books
[HttpGet]
public ActionResult<IEnumerable<Book>> GetBooks()
{
return _bookRepository.GetAll();
}
// GET: api/Books/5
[HttpGet("{id}")]
public ActionResult<Book> GetBook(int id)
{
var book = _bookRepository.GetById(id);
if (book == null)
{
return NotFound();
}
return book;
}
// POST: api/Books
[HttpPost]
public ActionResult<Book> CreateBook(Book book)
{
var createdBook = _bookRepository.Add(book);
// Return a 201 Created response with the new book and location header
return CreatedAtAction(nameof(GetBook), new { id = createdBook.Id }, createdBook);
}
// PUT: api/Books/5
[HttpPut("{id}")]
public IActionResult UpdateBook(int id, Book book)
{
if (id != book.Id)
{
return BadRequest();
}
var existingBook = _bookRepository.GetById(id);
if (existingBook == null)
{
return NotFound();
}
_bookRepository.Update(book);
return NoContent(); // 204 No Content
}
// DELETE: api/Books/5
[HttpDelete("{id}")]
public IActionResult DeleteBook(int id)
{
var book = _bookRepository.GetById(id);
if (book == null)
{
return NotFound();
}
_bookRepository.Delete(id);
return NoContent(); // 204 No Content
}
}
[ApiController] and [Route("api/[controller]")]: These attributes define the controller as an API controller and set the route for the controller. [controller] will be replaced with the controller's name (Books), resulting in the route api/Books.BookRepository: This is an instance of our BookRepository class, which handles the data access logic. In a real application, you would inject this dependency using ASP.NET Core's dependency injection system.GetBooks(): This action method handles the GET request to retrieve all books. It returns an ActionResult<IEnumerable<Book>>, which allows us to return different HTTP status codes (e.g., 200 OK) along with the data.