Exercise: Northwind Web API
Build Northwind's products API. Write an async controller with GET (all, by category, by id), POST, PUT and DELETE, each answering the right status code, and set up Program.cs to register the DAO and handle errors in one place.
Journeyman · ASP.NET Core · REST API · Updated
Northwind's products need an API, so other programs, such as a mobile app or a web page's JavaScript, can read and change them. The model and the Dapper DAO are written. You'll write the controller, and set up Program.cs.
Get the exercise code
Open this lesson's GitHub repository, github.com/ask-codey/exercise-northwind-web-api, also linked from the Exercise box beside the lesson. Click Code, then Download ZIP, and unzip it into your bootcamp folder. Or clone it with Git. Then open NorthwindApi.slnx in Visual Studio.
| File | What's in it |
|---|---|
NorthwindApi/Models/Product.cs |
A product, with its validation rules |
NorthwindApi/Data/IProductDao.cs, ProductDao.cs |
The products table, with async Dapper methods |
NorthwindApi/Errors/DatabaseConflictHandler.cs |
Answers SQL Server's constraint errors with 409 Conflict |
NorthwindApi/Controllers/ProductsController.cs |
For you to finish. Its requirements are in the comment at the top. |
NorthwindApi/Program.cs |
For you to finish, where the TODO comments are |
NorthwindApi/NorthwindApi.http |
Ten numbered requests, each with the answer to expect |
NorthwindApi.Tests |
Tests that start the API in memory, with a fake DAO |
The API uses your own Northwind database. If yours has another name, change the connection string in appsettings.json.
What to do
Program.cs:
- Register
ProductDaoas theIProductDao, with the connection string. - Add problem details, and register the
DatabaseConflictHandler. - Handle exceptions for the whole API.
ProductsController, every action async:
| Request | Answers |
|---|---|
GET /api/products |
200 with every product |
GET /api/products?categoryId=1 |
200 with that category's products |
GET /api/products/1 |
200 with the product, or 404 |
POST /api/products |
201 with the new product and its address, or 400 for an invalid one |
PUT /api/products/1 |
200 with the updated product, or 404 |
DELETE /api/products/1 |
204, or 404 |
Run the tests with Test > Run All Tests. Then run the API with Ctrl+F5, open NorthwindApi.http, and send its requests in order.
Hints
- An optional filter from the query string is a nullable parameter:
GetAll(int? categoryId). The DAO already knows what to do withnull. {id:int}in each route template matches whole numbers only.CreatedAtAction(nameof(GetById), new { id = added.ProductId }, added)answers201, with theLocationheader.- You don't need to check
ModelState:[ApiController]answers400for an invalid product before your action runs. - The tests use a fake DAO with three products, swapped in for
ProductDao. That works because the controller asks for anIProductDao, not aProductDao: the interface from Abstraction and Interfaces paying off. - Product 666 makes the fake DAO throw. Your API should answer
500problem details, without showing the exception's message.
When you're done
Every test passes, and the .http file's requests answer as their comments say. The last one is the best: deleting Chai, which orders still use, answers:
HTTP/1.1 409 Conflict
Content-Type: application/problem+json
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.10",
"title": "Conflict",
"status": 409,
"detail": "Other data uses this item, or it uses data that doesn't exist, so it can't be saved or deleted."
}
A database error, turned into a clear answer, without a single try in your controller.
Submit your exercise
The exercise is how you finish this lesson. When your work is done, put it on GitHub in a repo of your own, then submit that repo's address here.
On GitHub, click +, then New repository. Name it (for example
exercise-northwind-web-api), choose Public, and click Create repository. Leave out the README: your folder already has one.In a terminal in your exercise folder (Git Bash on Windows), send your work to your new repo. If you downloaded the ZIP:
git init -b main git add . git commit -m "My solution" git remote add origin https://github.com/your-name/exercise-northwind-web-api.git git push -u origin mainIf you cloned the starter instead, point your copy at your own repo, then commit and push:
git remote set-url origin https://github.com/your-name/exercise-northwind-web-api.git git add . git commit -m "My solution" git push -u origin mainPaste your repo's address, such as
https://github.com/your-name/exercise-northwind-web-api, into Submit your exercise on this page. The site checks that the repo is public and holds your commits, and then the lesson is complete.
Changed something after you submitted? Push it, and submit again: your latest submission is the one that counts.
So what
That's a complete, professional API: REST addresses, honest status codes, async all the way down, validation for free, and errors handled in one place. The next chapter writes the other side: a C# program that calls it.
Key terms
- REST
- ActionResult<T>
- Async/Await
- Exception Handling Middleware