Part 2: Creating a simple Web API
This continues on from the work done in part 1, if you haven't completed that, it's best to head over there. Alternatively, you can switch to the branch "Part01Final" (Team Explorer - Branches - right click "Part01Final" inside remotes/origin and select "New local branch from..." and give it a local name, tick Checkout branch and untick Track remote branch) to use our version of part 1.
Working towards our first Angular service
Continuing on with our exciting "list of things" from part 1, now we'd like to load a list of things from the server, send additional items to add to the list back to the server, and ask the server to remove things from the list. At the end of part 1, we had a user interface that could manage this, but all the data was simply local to the user's browser (if you refreshed the page, you'd see that it would reset back to where we started). Let's see how we can get this talking to the server.
Create the WebAPI end points
First things first, let's create the server-side API that we'll be talking to. In the top level Controllers folder of the AngularGettingStarted project, add a new Web API Controller class from the Server-side list in the Add new item dialog - call it ThingListController.cs.
In WebAPI, the attributes present on the classes and methods are used to define the URLs and HTTP methods which will reach those items. Take a look at the code generated when we create a new Web API Controller - here annotated with comments to explain what various features mean:
namespace AngularGettingStarted.Controllers { // Here, we define the basic URL used to reach all endpoints // inside this class - [controller] represents the name of the // classbefore the word Controller, so in this case: // "api/ThingList" is our base URL. We're also specifying // that, by default, nothing from this controller should be // cached by the browser. [Route("api/[controller]")] [ResponseCache(NoStore=true)] public class ThingListController : Controller { // If an HTTP GET comes in to api/ThingList, this method will // be used to handle it. You can see that it is simply // returning plain .NET objects, and the framework will deal // with marshalling that to JSON to return to the client. [HttpGet] public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } // If an HTTP GET comes in to api/ThingList/1234, this method // will handle it - you can see 1234 will be placed into the // id parameter here. In this case, it's simply returning a // hard-coded string. [HttpGet("{id}")] public string Get(int id) { return "value"; } // If an HTTP POST comes in to api/ThingList, which has the // meaning of "create me a new item within api/ThingList", // this method will handle it. [HttpPost] public void Post([FromBody]string value) { } // If an HTTP PUT comes in to api/ThingList/1234, which has // the meaning of "update the item 1234 with what I've sent", // this method will handle it. [HttpPut("{id}")] public void Put(int id, [FromBody]string value) { } // If an HTTP DELETE comes in to api/ThingList/1234, which // has the meaning of "remove the item 1234", this method // will handle it. [HttpDelete("{id}")] public void Delete(int id) { } } }
For our thing-list, we'll define the following three endpoints:
URL | Verb | Meaning |
---|---|---|
/api/thinglist | GET | Return all things in the list |
/api/thinglist | POST | Add a thing to the list - we'll supply the thing to add in the body of the request. |
/api/thinglist/{thing} | DELETE | Remove a particular thing from the list |
For this example, we'll store the values in a static string list in our controller - in a real-world application, we'd likely pass this data off to a database or similar to store. So, let's create that and replace the Get() method to return this list:
private static List<string> s_thingList = new List<string>(); [HttpGet] public List<string> Get() { return s_thingList; }
Now, let's implement our Post method to handle adding items to the list. In all but the very simplest of cases, a Post will take an object parameter rather than a raw value, so let's go ahead and create a new class named Thing in the Models folder, which will simply hold a string value:
public class Thing { public string Value { get; set; } }
And update our Post method to take a Thing parameter and put its value in the list - the [FromBody] annotation tells the framework to take the body from the post request and attempt to make a Thing out of it:
[HttpPost] public void Post([FromBody]Thing thing) { s_thingList.Add(thing.Value); }
Our API is now ready to run - we'll add the delete implementation shortly, but let's see it running first. To interact with a Web API for testing, it's useful to install the Postman Chrome extension which allows you to hand-craft HTTP requests and see the responses. Install that, then Debug your project and pop the URL http://localhost:43327/api/thinglist into Postman, you should see a response of [] - an empty array. Note that the port number in your instance may well be different - you can find the port used by your project in the Debug tab of its properties page in Visual Studio.
Let's try posting to our API to create a new entry in our list, so in Postman once more, set the request type to POST instead of GET (to the left of the URL), and in the Body tab, select raw with a type of "JSON (application/json)", then enter the following - noting that we're making a JSON structure that looks like the Thing class we defined above:
{ "Value": "sheep" }
Send that in, and you should see an empty response with the response code of 200 - that means the request was successful. To prove that it has actually worked, re-run your original GET and you should now see an entry in the list - [ "sheep" ] - if you ran your post multiple times, you will see multiple sheep!
The last thing to do for now, before we get back into our Angular code, is to create the delete handler. The URL to this will include the item we're deleting, so should look like the following:
[HttpDelete("{thing}")] public void Delete(string thing) { s_thingList.Remove(thing); }
Debug that up and check in Postman that, after creating an item using a POST, you can then delete that item using a DELETE and adjusting the URL to include the value you created (e.g. if you post { "Value": "horse" }, then you should send a DELETE to /api/thinglist/horse).
One final note - at the moment we're not checking that whatever has been POSTed is a valid Thing, so if you get the syntax wrong on your POST body, you may end up with null entries on the list. We'll have a look at that in due course.
You can check your solution against this branch which adds the Web API discussed in this page to our application.
With that, we're ready to get back to Angular, so head to Part 3 and we'll create a service to interact with this API.