Exercise: an Angular Client for a Web API
Give your products API a front end. A service calls the API with HttpClient; a component lists the products, filters them by category, deletes them and adds new ones, and says so when something fails. Ten tests answer for a pretend API, so they need nothing running.
Journeyman · Angular · REST API · Updated
In Exercise: Northwind Web API you built an API for Northwind's products. Now give it a front end: an Angular page that lists the products, filters them by category, deletes them and adds new ones.
Get the exercise code
Open this lesson's GitHub repository, github.com/ask-codey/exercise-an-angular-client-for-a-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. Open the folder in VS Code, and a terminal there:
npm install
npm test
The tests fail to start with.
| File | What's in it |
|---|---|
src/app/product.ts |
The Product interface, shaped like the API's JSON, and Northwind's eight categories. Finished. |
src/app/product-api.ts |
The service that calls the API, for you to finish |
src/app/product-list/product-list.ts |
The products page's class, for you to finish. Its requirements are in the comment at the top. |
src/app/product-list/product-list.html |
Its template, for you to finish |
src/app/client.spec.ts |
Ten tests |
proxy.conf.json |
Sends the app's /api requests to http://localhost:5179 while you develop |
The tests don't need your API running. They use Angular's HttpTestingController: it catches each request the app sends, and the test answers it, with products or with an error. So a test can check, for example, that choosing Condiments sends GET /api/products?categoryId=2, then answer with one product and check that the table shows just that one.
What to do
1. The service. Finish ProductApi:
getAll()sendsGET /api/products;getAll(2)sendsGET /api/products?categoryId=2;add(product)sendsPOST /api/productswith the product, and gives back the product the API sends back, with its new id;delete(7)sendsDELETE /api/products/7.
Each returns the observable from HttpClient. The component subscribes.
2. The page. Finish ProductList:
- while the products load, Loading products...; then a table, one row per product, with a Delete button;
- if loading fails, Sorry, the products couldn't be loaded (500)., with the real status;
- a Category list: choosing one loads that category's products, and All categories loads them all again;
- Delete removes the product with the API, and its row when the API answers;
- an Add a product form: name, price, category and an Add button. It adds the product the API sends back to the end of the table, and empties the form. Without a name, it says Give the product a name. and sends nothing.
The exact ids and classes the tests look for are in the comment at the top of product-list.ts.
Hints
- The service:
inject(HttpClient), thenthis.http.get<Product[]>(url),post<Product>(url, product)anddelete<void>(url). Build the URL with a template string. - The state: signals for the products, is it loading?, the message, and the chosen category.
subscribe({ next, error })sets them. - The status: the error is an
HttpErrorResponse, and itsstatusis the number for the message. - The category list:
[ngModel]="categoryId()" (ngModelChange)="chooseCategory($event)"shows the choice, and calls your method with the new one. The value is a string:''for all, or'2', so turn it into a number before calling the service. - After a delete or an add, change the list signal with
update, usingfilteror[...products, added], instead of loading everything again. - The form:
[(ngModel)]on each box, withFormsModulein the component'simports. Money:{{ product.unitPrice | currency }}, withCurrencyPipein the imports.
Try it for real
When the tests pass, start your API from Exercise: Northwind Web API (Ctrl+F5), and this app with ng serve. If your API isn't at port 5179, change the port in proxy.conf.json first. Open http://localhost:4200:
- All 77 products load. Choose Seafood, and there are 12.
- Add Trail Mix at 4.50 in Confections. It appears at the end of the table, and the form empties.
- Reload the page: Trail Mix is still there, because it's in the database. Delete it.
- Stop the API and choose another category. The message says the products couldn't be loaded, with the status
502, Bad Gateway: the dev server's proxy answered for the API it couldn't reach.
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-an-angular-client-for-a-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-an-angular-client-for-a-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-an-angular-client-for-a-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-an-angular-client-for-a-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
A service that only talks HTTP, a component that only shows signals, and tests that stand in for the server. That's the shape of every Angular page that reads and writes data, and the routing chapter next builds on it.
Key terms
- HttpClient
- Service
- Observable
- subscribe()