Complete REST API Capstone Project โ Product Management CRUD Masterclass
Welcome to Phase 12 (Chapter 35): Complete ASP.NET Core REST API Capstone Project โ Product Management CRUD System! This is the final capstone lesson that ties together everything learned in this masterclass. We build a complete, production-ready Product Management REST API using ASP.NET Core 8 with: Product model, ProductDto, IProductService interface, ProductService implementation, ProductsController with full CRUD, in-memory repository, data validation, proper HTTP status codes, and Swagger documentation.
// Models/Product.cs
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = "";
public decimal Price { get; set; }
public int Stock { get; set; }
public string Category { get; set; } = "";
}
// DTOs/CreateProductDto.cs
public class CreateProductDto
{
[Required, MinLength(2), MaxLength(100)]
public string Name { get; set; } = "";
[Required, Range(0.01, 10000000)]
public decimal Price { get; set; }
[Required, Range(0, int.MaxValue)]
public int Stock { get; set; }
[Required]
public string Category { get; set; } = "";
}
// Services/IProductService.cs
public interface IProductService
{
List<Product> GetAll();
Product? GetById(int id);
Product Create(CreateProductDto dto);
Product? Update(int id, CreateProductDto dto);
bool Delete(int id);
}
// Services/ProductService.cs
public class ProductService : IProductService
{
private readonly List<Product> _products = new()
{
new Product { Id = 1, Name = "Laptop", Price = 75000, Stock = 10, Category = "Electronics" },
new Product { Id = 2, Name = "Mouse", Price = 1200, Stock = 50, Category = "Accessories" },
new Product { Id = 3, Name = "Keyboard", Price = 2500, Stock = 30, Category = "Accessories" }
};
private int _nextId = 4;
public List<Product> GetAll() => _products;
public Product? GetById(int id) => _products.FirstOrDefault(p => p.Id == id);
public Product Create(CreateProductDto dto)
{
var product = new Product { Id = _nextId++, Name = dto.Name, Price = dto.Price, Stock = dto.Stock, Category = dto.Category };
_products.Add(product);
return product;
}
public Product? Update(int id, CreateProductDto dto)
{
var product = GetById(id);
if (product is null) return null;
product.Name = dto.Name;
product.Price = dto.Price;
product.Stock = dto.Stock;
product.Category = dto.Category;
return product;
}
public bool Delete(int id)
{
var product = GetById(id);
if (product is null) return false;
_products.Remove(product);
return true;
}
}
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly IProductService _service;
public ProductsController(IProductService service) // DI via constructor injection
{
_service = service;
}
// GET /api/products โ Get ALL products
[HttpGet]
public ActionResult<List<Product>> GetAll() => Ok(_service.GetAll());
// GET /api/products/1 โ Get ONE product
[HttpGet("{id:int}")]
public ActionResult<Product> GetById(int id)
{
var product = _service.GetById(id);
return product is null ? NotFound(new { Message = $"Product {id} not found." }) : Ok(product);
}
// POST /api/products โ CREATE product
[HttpPost]
public ActionResult<Product> Create([FromBody] CreateProductDto dto)
{
var product = _service.Create(dto);
return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}
// PUT /api/products/1 โ UPDATE product
[HttpPut("{id:int}")]
public ActionResult<Product> Update(int id, [FromBody] CreateProductDto dto)
{
var product = _service.Update(id, dto);
return product is null ? NotFound(new { Message = $"Product {id} not found." }) : Ok(product);
}
// DELETE /api/products/1 โ DELETE product
[HttpDelete("{id:int}")]
public IActionResult Delete(int id)
{
bool deleted = _service.Delete(id);
return deleted ? NoContent() : NotFound(new { Message = $"Product {id} not found." });
}
}
// Program.cs โ Register ProductService and run app
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddScoped<IProductService, ProductService>(); // Register DI
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI();
app.MapControllers();
app.Run();
Q1: What HTTP status codes should CRUD operations return?
GET โ 200 OK (found) / 404 Not Found; POST โ 201 Created; PUT โ 200 OK / 404 Not Found; DELETE โ 204 No Content / 404 Not Found; Validation error โ 400 Bad Request.
Q2: What is the next step after this masterclass?
Learn Entity Framework Core for database persistence, JWT Authentication for security, Fluent Validation, and deploy your API to Azure App Service or Docker containers.