2013-05-22 10 views
6

Eine der besten Vorgehensweisen beim Schreiben von RESTFul API-Anwendungen ist das Hinzufügen von Versionsverwaltung. Beispiel:REST Api-Implementierung mit Spring

http://my-server/api/v1/getData 
http://my-server/api/v2/getData 

Unsere Anwendung macht REST API mit dem Spring-Framework verfügbar. Wir markieren eine Klasse als Controller, verwenden die Annotation "RequestMapping", um URL einer Funktion zuzuordnen, und fügen einige Objekte hinzu, die in/aus JSON-Objekten übersetzt werden.

Zum Beispiel:

@RequestMapping(method = RequestMethod.POST, value = "/api/v1/getData") 
public @ResponseBody ResponseDataDTO getData(@RequestBody OperationsDetailsTDO details) {...} 

Jetzt wollen wir die zweite Version der API zur Verfügung zu stellen. Etwa 2/3 der Funktionen bleiben gleich und 1/3 ändern sich. Die Änderungen betreffen sowohl die Logik als auch die JSON-Objekte.

Ich frage mich, wie man den Code entwirft. Ich denke, dass diese Art von Code ist schwer zu verwalten:

@RequestMapping(method = RequestMethod.POST, value = "/api/{version-var}/getData") 
public @ResponseBody ResponseDataDTO createReleaseFromTemplate(@PathVariable("version-var") Integer version, @RequestBody OperationsDetailsTDO details) { 
if (version == 1) 
{ 
    doForVersion1(); 
} 
else if (version == 2) 
{ 
    doForVersion2(); 
} 

} 

Es wird schwer sein, zu verwalten, da es in jeder Funktion unterschiedliche Verzweigung sein. Nur um das Problem zu demonstrieren, wenn ich ein automatisches Tool habe, das Dokumentation generiert - es wird nicht verstehen können, was die API ist.

Zweitens frage ich mich, was ich mit den Klassen tun soll, die an JSON-Objekt gebunden sind. Muss ich alle diese Klassen für kleine Änderungen duplizieren?

Thx.

+0

In Verbindung stehende http://stackoverflow.com/questions/389169/best-practices-for-api-versioning – andyb

+0

Es ist eine andere API schließlich. Sie müssen alles ändern, das es verwendet. –

Antwort

1

ich mit Ihnen einverstanden Version als Parameter zur bestandenen, wie

@RequestMapping(method = RequestMethod.POST, value = "/api/{version-var}/getData") 

Aber ich glaube nicht, dass es eine gute Idee, viele Zweige hinzufügen, Wir sollten alle Methoden in der Ressourcenklasse extrahieren zu einer Business-Schnittstelle, wie

private IDataRetrieve dataRetriever; 
@RequestMapping(method = RequestMethod.POST, value = "/api/{version-var}/getData") 
public @ResponseBody ResponseDataDTO createReleaseFromTemplate(@PathVariable("version-var") Integer version, @RequestBody OperationsDetailsTDO details) { 
    dataRetiever = DataRetrieverFactory.getDataTrieverByVersion(version); //TODO, create a factory to get DataRetriever 
    return dataRetiever.getData(); 
} 

Und dann müssen Sie zwei klassiert IDataRetriver, (einen für V1, eine andere für v2) zu implementieren; Um doppelten Code zu vermeiden, können Sie natürlich eine abstrakte Klasse für V1 und V2 hinzufügen und Template Patern verwenden, um den duplizierten Code zu entfernen.

+0

+1 Ich bin nur nicht so begeistert von dem Präfix "I" für Schnittstellen. Ein Client sollte nicht wissen, dass er eine Schnittstelle oder eine Implementierung verwendet. – Bart

+0

und was ist mit den JSON-Objekten? Sie werden automatisch nach den relevanten Klassen generiert. Muss ich diese Klassen duplizieren? – Jonathan

+0

Ich glaube nicht, dass wir diese Klassen duplizieren müssen. ("Diese Klassen" bedeutet Einreise/Sicht Klassen, nicht wahr?). Wie ich dachte, die v1/v2 wird einige Geschäftslogik enthalten, die Rückkehr sollte gleich sein. Wenn v1 keine Methode unterstützt, werfen Sie einfach eine Ausnahme. – Stony

0

Sie können reguläre Ausdrücke in Ihrem RequestMapping verwenden, wenn Sie eine Pfadvariable für die Version verwenden (see here for example). Oder Sie können eine neue Methode erstellen, die einfach die alte aufruft, aber das neuere RequestMapping für v2 hat. Oder erstellen Sie eine generische Methode, die die Version ergreift und die richtige Methode aufruft, die diese Version der Anforderung tatsächlich verarbeitet. Bonus für die letzte Methode: Sie könnten die Version greifen und den Benutzer zu einem bestimmten Fehler schicken, wenn die Version, die sie senden, nicht unterstützt wird, zum Beispiel, wenn sie/app/v10/was auch immer senden.

+0

** a) ** Reguläre Ausdrücke sind nicht erforderlich. Warum also benutzen? ** b) ** Duplizieren Code überall ist nicht sehr überschaubar, wenn die Anzahl der API-Versionen wachsen. ** c) ** Sie können nicht einfach eine Version für eine andere ausgeben. Kunden benutzen diese APIs. – Bart

+0

a) Die Regex kann verwendet werden, um die Übereinstimmung der Anfrage-URL zu erleichtern. Das war, was der OP verlangte b) Niemand sagte, Code zu duplizieren. Er erstellt eine neue API, während er die alten zurücklässt. Das wäre neuer Code, oder? Ich glaube nicht, dass irgendetwas, das ich erwähnt habe, "Code duplizieren" erfordert und c) Niemand sagte, dump die v1.Ich sagte "Sie können Regex verwenden oder Sie können eine andere Methode für v2 in Ihrem Controller haben ODER Sie könnten Ihre Version in einen Pfad var ändern, haben Sie eine Methode, die dann auf die richtige zugrunde liegende Methode für die Version wechselt" – CodeChimp

+0

Übrigens, Ich glaube, was ich im letzten vorgeschlagen habe, war ähnlich dem, was @ Stonyzhang vorgeschlagen hat, nämlich die Version als Pfadvariable zu verwenden, um zu bestimmen, welche Version aufgerufen werden soll. Ich hatte angenommen, dass das OP Standard-OOP- und MVC-Praktiken verwendet, und irgendwo wäre eine "Service-Schicht" vorhanden. – CodeChimp

Verwandte Themen