Eigene API mit ASP.NET Core: Todo API

Normalerweise befasse ich mich ja meistens mit dem Frontend einer App, aber in diesem Beitrag möchte ich nun zeigen, wie man mit wenig Aufwand eine eigene kleine API mit der Hilfe von ASP.NET Core entwickeln kann. Das Ziel wird sein eine eigene kleine Todo-API zu entwickeln, wo man neue Einträge hinzufügen, die Einträge abrufen, den Status von offen auf erledigt ändern und einzelne Einträge auch löschen kann.

Wir öffnen zunächst Visual Studio und legen ein neues Projekt an. Als Template wählen wir den Eintrag ASP.NET Core Web Application aus.

Als Namen wähle ich TodoApi, aber ihr seid hier natürlich in der Namensgebung völlig frei. Gleichzeitig müssen wir noch den Ordner zum Speichern der Solution angeben und können dann mit einem Klick auf Create die Solution anlegen.

Im nächsten Schritt stellen wir sicher, dass .NET Core und ASP.NET Core 2.2 ausgewählt sind. Sollte dies nicht der Fall sein und euch die Version 2.2 auch nicht zur Verfügung stehen, könnt ihr diese bequem über diese Webseite installieren. Anschließend wählen wir noch API als Template und bestätigen die Eingabe mit einem Klick auf Create.

Wir öffnen die Klasse ValuesController im Ordner Controllers. Dieser wird standardmäßig angelegt und dient nur als Orientierung. Über das Attribute Route wird die jeweilige Route angegeben, also in diesem Fall /api/values. Die erste Methode Get() ist mit dem Attribute HttpGet deklariert, ist als per HTTP-Methode GET erreichbar und liefert uns ein Array bestehend aus value1 und value2 zurück. Unterhalb der Get-Methode finden wir eine weitere Get-Methode, welche jedoch einen Parameter entgegen nimmt. Im Attribute HttpGet wird noch ein String angegeben, welcher die Route angibt. Wie der Kommentar vermuten lässt, lautet diese z.B. nun /api/values/5. Durch die geschweiften Klammern wird automatisch auf den Parameter id gemappt und auch schon die Konvertierung von String auf Integer wird vorgenommen, so dass wir innerhalb der Methode mit diesem Wert arbeiten können.

Nun wollen wir aber unseren eigenen Todo-Controller anlegen. Dafür löschen wir zunächst den ValuesController, da wir diesen nicht mehr benötigen und klicken mit der rechten Maustaste auf den Controllers-Ordner und wählen Add – New Controller aus. Als Vorlage wählen wir im nächsten Schritt API Controller – Empty aus.

Im nächsten Schritt müssen wir einen Namen für unseren Controller angeben. Ich werde den Controller TodoController nennen.

Nun steht uns auch schon das Grundgerüst des Controllers  zur Verfügung und er ist bereits unter /api/todo erreichbar. Allerdings haben wir noch keine Methoden definiert, so dass wir keine Antwort von unserem Controller erhalten. Dies wollen wir aber jetzt ändern. Vorher müssen wir aber noch zwei zusätzliche Klassen für die Datenmodelle erstellen. Dazu legen wir einen neuen Ordner Models an und darin die Klasse TodoItem mit folgendem Inhalt:

public class TodoItem
{
    public string Id { get; set; }
    public string Content { get; set; }
    public bool IsDone { get; set; }
    public DateTime TimeStamp { get; set; }
}

Eine zweite Klasse erhält den Namen TodoItemDto und den folgenden Inhalt:

public class TodoItemDto
{
    public string Content { get; set; }
    public bool IsDone { get; set; }
}

Nun wechseln wir zurück zu unserem TodoController und fügen eine lokale Variable _todoItems hinzu, welche später unsere Todo-Items speichern soll.

private static List<TodoItem> _todoItems = new List<TodoItem>();

Zunächst brauchen wir eine Hilfsmethode, welche uns das TodoItem zu einer übergebenden Id zurückliefert.

private TodoItem GetTodoItem(string id)
{
    return _todoItems.FirstOrDefault(t => t.Id == id);
}

Nun schreiben wir unsere erste Methode, welche uns die vollständige Liste zurückliefert. Diese dekorieren wir mit dem Attribut HttpGet, da diese standardmäßig aufgerufen werden soll, wenn wir einen GET-Request auf die Route /api/todo machen. Die Methode ist relativ simpel, da einfach ein Ok-Objekt mit unserer lokalen Variablen zurückgegeben wird.

[HttpGet]
public IActionResult Get()
{
    return Ok(_todoItems);
}

Die nächste Methode soll uns nun ein einzelnes TodoItem abhängig von der Id zurückliefern. Diese soll ebenfalls über GET erreichbar sein, aber wir wollen noch eine Id übergeben. Daher erweitern wir das HttpGet-Attribut um die Route {id}, welche automatisch an unsere Methode übergeben wird. Hier nutzen wir nun unsere Hilfsmethode. Sollten wir kein TodoItem zu der Id finden, so geben wir ein NotFound, also Statuscode 404 zurück und ansonsten ein Ok-Objekt mit dem passenden TodoItem.

[HttpGet("{id}")]
public IActionResult GetById(string id)
{
    var todoItem = GetTodoItem(id);

    if (todoItem == null)
        return NotFound();

    return Ok(todoItem);
}

Wir sind nun in der Lage die TodoItems abzurufen, aber wir legen wir nun ein neues Objekt an? Hierzu wollen wir eine weitere Methode schreiben, welche über POST erreichbar ist und ein TodoItemDto-Objekt an unsere API übergibt. Dieses konvertieren wir dann in ein TodoItem und speichern es in unserer Liste ab. Anschließend liefern wir das vollständige Objekt wieder zurück. Die Konvertierung erfolgt hierbei direkt im Code und würde in einem Produktiv-Beispiel sicherlich über einen Mapping-Service erfolgen.

[HttpPost]
public IActionResult Add(TodoItemDto todoItemDto)
{
    var todoItem = new TodoItem
    {
        Id = Guid.NewGuid().ToString(),
        Content = todoItemDto.Content,
        IsDone = todoItemDto.IsDone,
        TimeStamp = DateTime.Now
    };

    _todoItems.Add(todoItem);

    return Ok(todoItem);
}

Wir wollen unsere Todo-Items auch löschen können. Daher brauchen wir eine Methode, welche über DELETE erreichbar ist und das Element aus der Liste entfernt.

[HttpDelete("{id}")]
public IActionResult Delete(string id)
{
    var todoItem = GetTodoItem(id);

    if (todoItem == null)
        return NotFound();

    _todoItems.Remove(todoItem);

    return Ok();
}

Zu guter Letzt benötigen wir noch eine Methode, welche den Status unseres Todo-Items ändert. Hierzu bietet sich eine Methode, welche über PUT erreichbar ist, an, welche einfach die Property IsDone toggelt und den Zeitstempel aktualisiert. Um später vielleicht eine weitere Methode zum Ändern des Textes anbieten zu können, geben wir die Route auf /api/todo/status/{id} an.

[HttpPut("status/{id}")]
public IActionResult Update(string id)
{
    var todoItem = GetTodoItem(id);

    if (todoItem == null)
        return NotFound();

    todoItem.IsDone = !todoItem.IsDone;
    todoItem.TimeStamp = DateTime.Now;

    return Ok(todoItem);
}

Damit sind wir mit einer ersten Version unseres Controllers bereits fertig und wir können mit dem Testen beginnen. Dazu einfach in Visual Studio im oberen Bereich auf Play-Button klicken. Nun empfiehlt es sich zum Beispiel mit Postman ein paar Requests gegen unsere API zu machen.

Natürlich hat unser Controller noch ein paar Probleme, denn sobald wird die Ausführung des Backends stoppen sind auch unsere Daten verloren, denn diese werden derzeit nur im Speicher vorgehalten. Aber um diese Erweiterung werden wir uns in einem späteren Beitrag kümmern.

Die aktuelle Version des Codes findet ihr auch auf GitHub und ich wünsche euch nun viel Spaß beim Erweitern des Codes und dem Entwickeln eurer eigenen API.

Pokédex – Kleines Xamarin.Forms Projekt – Teil 1 MVVM Code mit Source Generatoren vereinfachen Azure Functions im Docker Container