Hi,
Im Rahmen einer Webservices Vorlesung habe ich diverse Dokumentationen für REST APIs geschrieben und ich dachte ich teile das hier mit euch.
Was ist REST?
= Representational State Transfer
REST ist eine Abstraktion der Struktur und des Verhaltens des Word Wide Webs. Bei REST wird über die Zugriffsmethode des Protokolls sowie einer URI eine Repräsentation oder Modifikation einer Ressource angefragt.
REST setzt auf dem HTTP Protokoll auf, was sehr günstig ist da das Protokoll bereits REST konform arbeitet. REST Services sind zustandslos, d.h. der Server speichert keine Zwischenzustände zwischen zwei Anfragen. Das bringt den Vorteil das REST-APIs sehr hoch skalierbar sind, da die Last auf mehrere Rechner verteilt werden kann, da alle Informationen die vom Client benötigt werden in der Anfrage enthalten sind.
HTTP gestüztes REST bietet diese Methoden:
ACHTUNG: Richtige REST-APIs müssen das HATEOAS (Hypermedia As The Engine Of Application State) Prinzip implementieren. Das heißt das die Ressourcen, ähnlich wie im World Wide Web, untereinander verlinkt sein sollen.
Einfaches Beispiel einer Kunden-Verwaltung:
Das hat zur Folge, dass man anhand des links auf alle Orders des Kunden sofort zugreifen kann ohne aus der OrderID und der API Dokumentation selbst eine URL zusammenbasteln muss.
Für die Verlinkung verwendet das folgende Beispiel den SIREN Formatter (die notwendigen Klassen hänge ich unten an). Siren kapselt alle Entitäten mit zugehörigen Eigenschaften in generische Objekte. Diese Objekte erhalten sogenannte Links zueinander. Außerdem hat jede Entität zusätzlich sogenannte Actions, d.h. eine Auflistung aller Operationen, die die API auf dem angefragten Objekt anbietet.
Erstellung einer REST-API
Das wars auch schon :), damit ist ein erstes sehr grundlegendes Beispiel einer REST-API fertig.
Wie versprochen hänge ich unten noch die beiden Klassen an.
Im Rahmen einer Webservices Vorlesung habe ich diverse Dokumentationen für REST APIs geschrieben und ich dachte ich teile das hier mit euch.
Was ist REST?
= Representational State Transfer
REST ist eine Abstraktion der Struktur und des Verhaltens des Word Wide Webs. Bei REST wird über die Zugriffsmethode des Protokolls sowie einer URI eine Repräsentation oder Modifikation einer Ressource angefragt.
REST setzt auf dem HTTP Protokoll auf, was sehr günstig ist da das Protokoll bereits REST konform arbeitet. REST Services sind zustandslos, d.h. der Server speichert keine Zwischenzustände zwischen zwei Anfragen. Das bringt den Vorteil das REST-APIs sehr hoch skalierbar sind, da die Last auf mehrere Rechner verteilt werden kann, da alle Informationen die vom Client benötigt werden in der Anfrage enthalten sind.
HTTP gestüztes REST bietet diese Methoden:
GET | Fordert die angegebene Ressource vom Server an. GET weist keine Nebeneffekte auf. Der Zustand am Server wird nicht verändert, weshalb GET als sicher bezeichnet wird. |
POST | Fügt eine neue (Sub-)Ressource unterhalb der angegebenen Ressource ein. Da die neue Ressource noch keinen URI besitzt, adressiert der URI die übergeordnete Ressource. Als Ergebnis wird der neue Ressourcenlink dem Client zurückgegeben. POST kann im weiteren Sinne auch dazu verwendet werden, Operationen abzubilden, die von keiner anderen Methode abgedeckt werden. |
PUT | Die angegebene Ressource wird angelegt. Wenn die Ressource bereits existiert, wird sie geändert. |
PATCH | Die angegebene Ressource wird angelegt. Wenn die Ressource bereits existiert, wird sie geändert. |
DELETE | Löscht die angegebene Ressource. |
ACHTUNG: Richtige REST-APIs müssen das HATEOAS (Hypermedia As The Engine Of Application State) Prinzip implementieren. Das heißt das die Ressourcen, ähnlich wie im World Wide Web, untereinander verlinkt sein sollen.
Einfaches Beispiel einer Kunden-Verwaltung:
GET some/api/Customer/1
würde idealerweise eine solche Antwort zurückgeben:Das hat zur Folge, dass man anhand des links auf alle Orders des Kunden sofort zugreifen kann ohne aus der OrderID und der API Dokumentation selbst eine URL zusammenbasteln muss.
Für die Verlinkung verwendet das folgende Beispiel den SIREN Formatter (die notwendigen Klassen hänge ich unten an). Siren kapselt alle Entitäten mit zugehörigen Eigenschaften in generische Objekte. Diese Objekte erhalten sogenannte Links zueinander. Außerdem hat jede Entität zusätzlich sogenannte Actions, d.h. eine Auflistung aller Operationen, die die API auf dem angefragten Objekt anbietet.
Erstellung einer REST-API
- Erstellung der Basisklassen, die der Service anbieten soll. In unserem Fall die Customer-Klasse:
- Implementierung der Datenquelle, z.B. mit Hilfe des Repository-Patterns:
C#-Quellcode
- public static class CustomerRepository
- {
- private static readonly Dictionary<int, Customer> s_Repository = new Dictionary<int, Customer>();
- static CustomerRepository()
- {
- var c1 = new Customer { Id = 1, Name = "Hugo", LastContact = new System.DateTime(2016, 3, 21, 12, 30, 23) };
- s_Repository.Add(c1.Id, c1);
- s_Repository.Add(2, new Customer { Id = 2, Name = "Gabi", LastContact = new System.DateTime(2016, 3, 22, 11, 40, 53) });
- s_Repository.Add(3, new Customer { Id = 3, Name = "Chelsea Manning", LastContact = new System.DateTime(2017, 10, 1, 12, 30, 23)});
- s_Repository.Add(4, new Customer { Id = 4, Name = "Lars Kaufmann" });
- }
- public static IEnumerable<Customer> GetAll()
- {
- return s_Repository.Values;
- }
- public static Customer Get(int id)
- {
- return s_Repository[id];
- }
- public static void Add(Customer customer)
- {
- s_Repository.Add(customer.Id, customer);
- }
- public static void Update(Customer customer)
- {
- s_Repository[customer.Id] = customer;
- }
- public static void Delete(int id)
- {
- s_Repository.Remove(id);
- }
- public static bool TryGetValue(int id, out Customer customer)
- {
- return s_Repository.TryGetValue(id, out customer);
- }
- }
An dieser Stelle würde man hier eine Verbindung zu einer Datenbank aufbauen o.ä. aber um das ganze replizierbar zu machen verwendet das Beispiel statische Daten. - Siren und SirenFormatter importieren, an den beiden Klassen muss nichts geändert werden. In der StartUp.cs muss allerdings der SirenFormatter noch ausgewählt werden:
- Erstellen des Controllers. Idealerweise hat jedes Objekt der Domäne einen eigenen Controller.
GET api/Customer
liefert eine Liste aller Kunden
GET api/Customer/1
liefert den Kunden mit der ID 1
POST api/Customer
fügt einen neuen Kunden hinzu
POST api/CustomerFavourites
makiert einen Kunden als Favoriten
C#-Quellcode
- //URI Route des Controllers, Wenn [Controller] verwendet wird dann ist es api/<Klassenname - Controller>
- [Route("api/[Controller]")]
- public class CustomersController : Controller
- {
- //Operationen Route unter Name angeben
- [HttpGet(Name = Routes.CUSTOMERS_GETAllCUSTOMER)]
- public IActionResult Get()
- {
- //Neues Siren Objekt erstellen
- var siren = new Siren();
- //Verwendete Klassen hinzufügen
- siren.Class.Add("Customers");
- siren.Class.Add("Collection");
- foreach (var customer in CustomerRepository.GetAll())
- {
- //Entities befüllen und in Siren geben, mit Self-Link
- var entity = new EmbeddedRepresentation();
- entity.Class.Add("CustomerOverview");
- entity.Properties.Add(new Property { Name = "Name", Value = customer.Name });
- entity.Properties.Add(new Property { Name = "LastContact", Value = customer.LastContact });
- entity.Properties.Add(new Property { Name = "IsFavorite", Value = customer.IsFavorite });
- //Self Link hinzufügen
- entity.Links.Add(new Link
- {
- Relation = new List<string> { "self" },
- Href = Url.Link(Routes.CUSTOMERS_GETCUSTOMER, new { id = customer.Id })
- });
- siren.Entities.Add(entity);
- }
- //Aktionen hinzufügen
- siren.Links.Add(new Link
- {
- Relation = new List<string> { "self" },
- //Nur Null wählen wenn keinerlei Pfad Parameter wie api/Customer/1 benötigt werden
- Href = Url.Link(Routes.CUSTOMERS_GETAllCUSTOMER, null)
- });
- return Ok(siren);
- }
- //Hier wird die ID des Kunden benötigt
- [HttpGet("{id}", Name = Routes.CUSTOMERS_GETCUSTOMER)]
- public IActionResult Get(int id)
- {
- try
- {
- //Objekt anhand von ID aus Repo holen
- var customer = CustomerRepository.Get(id);
- //Siren Objekt erstellen
- var siren = new Siren();
- // Verwendete Klaasen hinzufügen
- siren.Class.Add("Customer");
- //Properties Hinzufügen
- siren.Properties.Add(new Property { Name = "Name", Value = customer.Name });
- siren.Properties.Add(new Property { Name = "LastContact", Value = customer.LastContact });
- siren.Properties.Add(new Property { Name = "IsFavorite", Value = customer.IsFavorite });
- // Self-Link zur Methode hinzufügen
- siren.Links.Add(new Link
- {
- Relation = new List<string> { "self" },
- Href = Url.Link(Routes.CUSTOMERS_GETCUSTOMER, new { id = customer.Id })
- });
- //Alle Sonstigen Methoden hinzufügen
- if (!customer.IsFavorite)
- {
- siren.Actions.Add(new Action
- {
- Name = "MarkAsFavorite",
- Method = "POST",
- Href = Url.Link(Routes.CUSTOMERS_MARKASFAVORITE, null)
- });
- }
- siren.Actions.Add(new Action
- {
- Name = "Move",
- Method = "POST",
- Href = Url.Link(Routes.CUSTOMERS_MOVE, new { id = customer.Id })
- });
- return Ok(siren);
- }
- catch (KeyNotFoundException)
- {
- return NotFound();
- }
- }
- //Einfügen eines neuen Customers über POST
- [HttpPost]
- public void Post([FromBody]Customer customer)
- {
- CustomerRepository.Add(customer);
- }
- }
- public static class Routes
- {
- public const string CUSTOMERS_MARKASFAVORITE = "CUSTOMERS_MARKASFAVORITE";
- public const string CUSTOMERS_GETAllCUSTOMER = "CUSTOMERS_GETAllCUSTOMER";
- public const string CUSTOMERS_GETCUSTOMER = "CUSTOMERS_GETCUSTOMER";
- }
- Erstellen von Controllern für spezifische Operationen auf einen Objekt der Domäne:
Das wars auch schon :), damit ist ein erstes sehr grundlegendes Beispiel einer REST-API fertig.
Wie versprochen hänge ich unten noch die beiden Klassen an.
faxe1008
Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „faxe1008“ ()