Lesson 3 Lab — MenuItemsController (Full CRUD)¶
Build a MenuItemsController with all five CRUD operations, following the
finished StaffController from the guide as your model. MenuItem has no
password, so there's no BCrypt here — it's the plainest possible full-CRUD
entity.
MenuItem has a CategoryId, but for this lesson treat it as just an integer
column — a plain foreign-key value. In the next lesson you'll learn how to return
the related Category object alongside it.
The MenuItem entity¶
Add Models/MenuItem.cs:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace TableServe.Api.Models;
public class MenuItem
{
public int Id { get; set; }
[StringLength(30)]
public string Name { get; set; } = string.Empty;
[Column(TypeName = "decimal(11,2)")]
public decimal Price { get; set; }
public int CategoryId { get; set; }
}
Steps¶
- Add
MenuItem.cstoModels/ - Add
DbSet<MenuItem> MenuItemstoTableServeDbContext - Run
Add-Migration AddMenuItemthenUpdate-Database - Verify the
MenuItemstable exists in SQL Server Object Explorer - Seed some menu items (Categories must already exist from the Lesson 2 lab):
INSERT INTO [dbo].[MenuItems] ([Name], [Price], [CategoryId]) VALUES ('Mozzarella Sticks', 9.99, 1)
INSERT INTO [dbo].[MenuItems] ([Name], [Price], [CategoryId]) VALUES ('Spinach Artichoke Dip', 11.99, 1)
INSERT INTO [dbo].[MenuItems] ([Name], [Price], [CategoryId]) VALUES ('Grilled Salmon', 21.99, 2)
INSERT INTO [dbo].[MenuItems] ([Name], [Price], [CategoryId]) VALUES ('Classic Burger', 14.99, 2)
INSERT INTO [dbo].[MenuItems] ([Name], [Price], [CategoryId]) VALUES ('Caesar Salad', 7.99, 3)
INSERT INTO [dbo].[MenuItems] ([Name], [Price], [CategoryId]) VALUES ('Chocolate Lava Cake', 8.99, 4)
INSERT INTO [dbo].[MenuItems] ([Name], [Price], [CategoryId]) VALUES ('Iced Tea', 3.99, 5)
- Create
Controllers/MenuItemsController.cswithGetAll,GetById,Create,Update,Delete— same shape asStaffController, minus the password hashing - Run the project and verify your endpoints using the MenuItems folder in the Insomnia collection
Verify in Insomnia¶
With the project running (no login required — the endpoints are open), expand the MenuItems folder:
- Get All Menu Items → expect 200 OK with an array
- Get Menu Item by Id → expect 200 OK with Mozzarella Sticks
- Create Menu Item → expect 201 Created with a generated
id - Update Menu Item → expect 200 OK with the changed fields
- Delete Menu Item → expect 204 No Content
- Check the Tests tab on each response — all green
You just wrote your first full-CRUD controller on your own. This is exactly the
pattern you'll repeat when you build ProductsController on PRS in the capstone — same
five methods, a PartNumber and VendorId instead of a CategoryId.
Stretch challenges¶
Optional — for when you finish early. Not needed for the capstone. [Reinforce] builds on what you just did; [Reach] goes past the guide and needs some research.
- Search endpoint — [Reinforce] — add an optional
?name=filter toGetAllthat returns only menu items whoseNamecontains the search text. - Reject duplicates — [Reinforce] — before creating, fetch to check no menu
item with the same
Namealready exists (the same "confirm by fetch" idea you use everywhere else), and returnBadRequestwith a message if it does. - Model validation — [Reach] — add data-annotation attributes (
[Required],[StringLength],[Range]onPrice) to the model and watch[ApiController]return a400automatically when they're violated. Not covered in the guide — research: Model validation in ASP.NET Core.
Finished these and want more? See stretch-api-challenges.md for bigger challenges that span the whole API pass.