[ASP.NET CORE] – My Road trip to ASP.NET Core – Building first API

So you have started a real Asp.net core project. This blog post shows you how to build a simple To-do list API yourself

1. Overview

If you don’t know what an API is

API stands for Application Programming Interface, a kind of interface that lets you interact with some data.

Take Uber for example: open the Uber app and you see a few Uber cars parked around you. How does Uber know this? By sending your GPS coordinates to the server, and the server returns the positions of the free cars around you. The Uber app pins them on the map.

Here are the APIs we are going to build

API Description Request body Response body
GET /api/todo Get all to-do items None Array of to-do items
GET /api/todo/{id} Get an item by ID None To-do item
POST /api/todo Add a new item To-do item To-do item
PUT /api/todo/{id} Update an existing item To-do item None
DELETE /api/todo/{id} Delete an item. None None

The diagram

Notes

View: the app / web that will use the API. For now we don’t care about it

Model: your data type. In this example the Model is the To-do item

Controller: the thing that receives the HTTP Request and produces the HTTP Responses. This example has only 1 controller

This example also doesn’t use a Database; it stores things directly in memory. A complete API would have a Database with it

2. Tools

To make debugging and testing the API you built easier, you can use a few tools

2.1. Fiddler

Download and install it here: https://www.telerik.com/download/fiddler

2.2. Google Chrome

Google Chrome is pretty good for all kinds of testing

3. Start

3.1. Creating the Project

Create a new project, pick the ASP.NET Core Web Application (.NET Core) template, name it todoapi > OK

Pick the Web API template > OK

3.2. Adding the model

A model is an object representing your data in the app. In this example the only model is a to-do item.

Tips: you should put all your models in their own folder, same as views and controllers (there is already a folder for controllers)

Right click the Project > Add > New Folder

Then right click the Models Folder > Add > Class, name the class TodoItem > Ok

Add 3 Properties

public string Key { get; set; }
public string Name { get; set; }
public bool IsComplete { get; set; }

3.3. Adding the Repository

A Repository — a place to store something — is a brand new technique in ASP.NET core. According to their documentation, a Repository is used to encapsulate data and hold the logic for accessing that data and passing it on to the Entity Model.

Even though our app has no database, it’s still nice to understand how this pile of code works

To start, we create a repository interface named ITodoRepository, using the add-class approach above but picking the Interface template

namespace todoapi.Models
{
    public interface ITodoRepository
    {
        void Add(TodoItem item);
        IEnumerable<TodoItem> GetAll();
        TodoItem Find(string key);
        TodoItem Remove(string key);
        void Update(TodoItem item);
    }
}

This interface defines the CRUD methods (Create - Read – Update – Delete)

Next we add the TodoRepository class, implementing the methods in the Interface we just created

public class TodoRepository : ITodoRepository
{
    private static ConcurrentDictionary<string, TodoItem> _todos = new ConcurrentDictionary<string, TodoItem>();
    public TodoRepository()
    {
        Add(new TodoItem { Name = "Item1" });
    }
 
    public void Add(TodoItem item)
    {
        item.Key = Guid.NewGuid().ToString();
        _todos[item.Key] = item;
    }
 
    public IEnumerable<TodoItem> GetAll()
    {
        return _todos.Values;
    }
 
    public TodoItem Find(string key)
    {
        TodoItem item;
        _todos.TryGetValue(key, out item);
        return item;
    }
 
    public TodoItem Remove(string key)
    {
        TodoItem item;
        _todos.TryGetValue(key, out item);
        _todos.TryRemove(key, out item);
        return item;
    }
 
    public void Update(TodoItem item)
    {
        _todos[item.Key] = item;
    }
}

Once that’s done, build it to see whether anything is broken

If the build comes out like this, it’s okay

3.4. Registering the Repository

By declaring the repository Interface, we can separate the repository class from the controller that uses it. Instead of creating an instance of TodoRepository inside the controller, we can poke the ITodoRepository straight into ASP.NET so we can use Dependency Injection later (don’t know what that is yet? documentation here: https://docs.asp.net/en/latest/fundamentals/dependency-injection.html)

This approach makes writing Unit Tests easier. The tests narrow down to the controller’s logic instead of testing the data access.

To poke (inject) it into the controller, we have to register it. Open the Startup.cs file and add the following line at the top

using todoapi.Models;

In the configureServices method, add the following code at the end

//Add our repository type
services.AddSingleton<ITodoRepository, TodoRepository>();

3.5. Adding the controller

Right click the Controller folder > Add > New Item

Pick Web API Controller Class and name it TodoController

Delete all the code in the class and replace it with this

public class TodoController : Controller
{
    public ITodoRepository TodoItems { get; set; }
 
    public TodoController(ITodoRepository todoItems)
    {
        TodoItems = todoItems;
    }
}

So you have declared a controller with nothing inside it. In the next sections we’ll add the methods that implement the API.

3.6. Getting to-do items

Add the following methods to TodoController

public IEnumerable<TodoItem> GetAll()
{
    return TodoItems.GetAll();
}
 
[HttpGet("{id}", Name = "GetToDo")]
public IActionResult GetById(string id)
{
    var item = TodoItems.Find(id);
    if (item == null)
    {
        return NotFound();
    }
    return new ObjectResult(item);
}

This gives us 2 gets

  • GET /api/todo
  • GET /api/todo/{id}

Here is an example of the HTTP Response when calling the GetAll method

HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Server: Microsoft-IIS/10.0 Date: Thu, 18 Jun 2015 20:51:10 GMT Content-Length: 82

[{“Key”:”4f67d7c5-a2a9-4aae-b030-16003dd829ae”,”Name”:”Item1”,”IsComplete”:false}]

Later we’ll use Fiddler to test these methods

4. Routing and URL Paths

In the method above you’ll see [HttpGet]. This is called an Attribute, and this Attribute marks the method below it as a Get. The Url path is built like this

  • Take the string in the Controller’s Route: [Route(“api/[controller]”)]
  • Drop the [controller] part and replace it with the controller’s name (minus the word “Controller”, of course). For TodoController you just put Todo in
  • If the HttpGet has a template string, append that string to the path. The example above doesn’t have one

In the GetId method above, “{id}” is a placeholder value. When making the request, the client substitutes the TodoItem’s Id there.

5. Return values

The GetAll method returns a CLR Object type. MVC automatically turns it into JSON and writes the JSON into the Response message’s body. The Response code is 200. If there is an unhandled exception, the response code is 5xx

  • If no item has such an Id, it returns response code 404. This is defined by the NotFound() method

6. Adding the other CRUD methods

6.1. Create

[HttpPost]
public IActionResult Create([FromBody] TodoItem item)
{
    if (item == null)
    {
        return BadRequest();
    }
    TodoItems.Add(item);
    return CreatedAtRoute("GetTodo", new {id = item.Key}, item);
}

The Post method

[FromBody] tells MVC that the TodoItem comes from the request message’s body

Return CreatedAtRoute: returns the address of that item as well

6.2. Update

[HttpPut("{id}")]
public IActionResult Update(string id, [FromBody] TodoItem item) 
{
    if (item == null || item.Key != id) 
    {
        return BadRequest();
    }
 
    var todo = TodoItems.Find(id);
    if (todo == null) 
    {
        return NotFound();
    }
    TodoItems.Update(item);
    return new NoContentResult();
}

Update is a lot like Create, but uses HttpPut. The standard Response is 204 (No Content)

According to the HTTP documentation, a Put request requires the client to send the whole content of the item being updated, not a few scattered fields. To update only one field, use HttpPatch

6.3. Delete

[HttpDelete("{id}")]
public void Delete(string id)
{
    TodoItems.Remove(id);
}

Void returns a 204 (No Content) response. Which means the client gets 204 whether the Item was deleted or the item never existed

That’s it — wait for the next post