Restful Service - Design Frage

hendr1k1

Ensign
Registriert
Aug. 2009
Beiträge
182
Moin,

ich bin dabei einen Rest Service zu programmieren. Ich habe eine Ressource Test und eine Result. In der DB ist in der Tabelle Result eine Foreign Key auf Test.

Es geht um den Fall, dass ich ein neues Result eintragen will per put request und der Test nicht in der DB vorhanden ist (Der Testname und Beschreibung sind dem client bekannt).

Option 1: Ich mache zuerst ein put request an die Ressource Test und erzeuge somit einen neuen Test. Anschließend mache ich einen put request auf die Ressource Result und übergebe die ID des Tests.

Option 2: Ich mache einen put request an die Ressource Result und übergebe den den Testnamen und Beschreibung mit, sodass der Server im Bedarfsfall den Test erstellen kann. Existiert der Test schon, dann erzeugt er natürlich nur ein neues Result.

Beides ist möglich aber was ist der sauberere, bessere Weg?

Ich persönlich würde Option 1 nehmen, da ich dort die Ressourcen getrennt behandel und der put request sauberer wird.
 
Puh ich habe die Frage jetzt 5 mal durchgelesen und es ist mir immer noch nicht ganz klar, worauf du hinaus willst.

So wie ich es verstanden habe geht es dir darum, dass du nicht weißt, ob es ok ist, dass bei Option 2 mit einem Request 2 Objekte / Ressourcen angelegt werden.

Ich würde sagen, dass es für beide Fälle eine Berechtigung gibt. Fall 1 ist technisch einfacher mit dem Nachteil dass du ggf. zwei Requests absetzen musst. Fall 2 ist vielleicht eine Spur benutzerfreundlicher, allerdings ist es schwieriger zu programmieren.
 
Das ist Geschmackssache.

Allerdings solltest du dir ein paar Fragen stellen (und beantworten):
1. Kommt es überhaupt vor, dass man einen einzelnen Test ohne Result anlegt?
2. Ist es überhaupt erlaubt einen Test ohne Result zu haben?
3. Ist das ganze irgendwie Performancekritisch?

Wenn du auf die ersten beiden Fragen mit JA antwortest, dann bist du so oder so gezwungen 2 separate URLs einzurichten.
Wenn du auf Frage 2 mit NEIN antwortest, dann würdest du die Logik deines Programms aushebeln, wenn du 2 URLs anlegst.

Vermutlich soll es zu jedem Test mehrere Results geben können. Daher würde ich auf jeden Fall eine URL einrichten, die folgendes (JSON)-Dokument entgegennimmt:
Code:
test: {
  name: "blabla",
  results: [
    {result1},
    {result2},
    ...
  ]
}
Falls der Fall, dass man einen Test mit mehreren Results auf einmal anlegen kann, vorkommt, würde das hier eine Menge Aufwand und Overhead durch HTTP sparen.


Im allgemeinen können die meisten REST Services aber automatisch unterscheiden, ob Child-Elemente vorhanden sind. Also in deinem Fall würde die Test-Resource einen neuen Test anlegen und falls direkt Results mitgeschickt wurden, werden die damit verknüpft und auch gespeichert. Das macht die Handhabung auf der Clientseite wesentlich einfacher - da universelle API.


Also noch mal deutlich: Wenn es möglich sein soll einen Test ohne Results anzulegen, aber auch einen Test mit Results, würde ich folgendes machen:
POST /tests legt einen neuen Test an, dabei kann es sowohl NUR ein Test sein, als auch ein Test mit eingebetteten Results
Und um nachträglich Results einzufügen:
POST /tests/4/results legt für den Test mit ID=4 ein neues Result ab, aber auch hier sollte es möglich sein ein Array von Results zu übergeben.

Wichtig: POST /results ist NICHT sinnvoll, da von außen nicht sichtbar ist, wo das Result abgelegt ist. GET /results hingegen ist legitim.


P.S. die gewünschte HTTP Methode ist POST und nicht PUT ;)

P.S. #2 es ist nicht sinnvoll URLs tiefer als 1 Ebene zu verschachteln - aus Gründen der Übersicht. Sicherlich mag es seltene Ausnahmefälle geben. Aber im Allgemeinen max. 1 Ebene.



Komplette Liste der von mir präferierten Routen:
Code:
# Für Read/Create:
GET /tests
GET /tests/:id
GET /tests/:id/results
GET /tests/:id/results/:id
POST /tests
POST /tests/:id/results
GET /results
GET /results/:id

# Für Update/Delete:
PUT /tests/:id
PUT /tests/:id/results/:id
PUT /results/:id
DELETE /tests/:id
DELETE /tests/:id/results/:id
DELETE /results/:id

Die /results und /results/:id URLs ergeben nur Sinn, wenn auf ein Result(-Set) unabhängig vom Test zugegriffen werden kann/soll. Keine Ahnung, ob das für deinen Fall Sinn ergibt.
 
Zuletzt bearbeitet:
Zurück
Oben