2016-08-17 3 views
3

Ich habe eine AngularJS Anwendung mit ui Router zu verwenden, die eine REST API mit Hyper verbraucht. Die allgemeine Idee ist, dass die API die URLs für ihre verschiedenen Aufrufe generiert und den Client daran hindert, die URLs selbst zu erstellen.AngularJS mit Hypermedia (HATEOAS): Wie hypermedia Urls accross Staaten

Wenn zum Beispiel die Liste der Produkte zu holen, ist hier, was die API gibt:

[ 
    { 
    "id": 1, 
    "name": "Product A", 
    "_links": { 
     "self": { 
     "href": "http://localhost:4444/api/products/1", 
     "name": null, 
     "templated": false 
     }, 
     "actions": [] 
    } 
    }, 
    { 
    "id": 2, 
    "name": "Product B", 
    "_links": { 
     "self": { 
     "href": "http://localhost:4444/api/products/2", 
     "name": null, 
     "templated": false 
     }, 
     "actions": [] 
    } 
    } 
] 

Also, das Problem: Ich eines Produkts zum Detail zu navigieren möchten. Ich habe die API-URL aus der Sammlung Hypermedia verfügbar. Beim Ändern von Zuständen muss ich diese URL jedoch irgendwie an den Detailzustand übergeben, damit der Controller des Detailzustands das Produkt abrufen kann.

Die UI-URLs sind vollständig von den API-URLs entkoppelt, d. H. Der Client hat sein eigenes URL-Schema.

Was ist der beste Weg, um dies zu erreichen, während der Client bleibt staatenlos und jede Seite bookmarkbar?

Eine Lösung besteht darin, die URL ui router 's data Eigenschaft zu übergeben. Die Seite wäre jedoch nicht bookmarkbar. Eine andere Möglichkeit besteht darin, die API-URL in der UI-URL zu übergeben, wodurch die Seite mit einem Lesezeichen versehen werden kann (solange sich die API-URL nicht ändert), aber die UI-URL wäre sehr hässlich.

Irgendwelche anderen Gedanken?

Wenn ich nicht falsch liege, suche ich nicht nach einer Vorlagenlösung, d. H. Einer Lösung, bei der die API eine Vorlage einer URL zurückgibt, die vom Client mit Parametern injiziert werden muss. Der springende Punkt ist, dass die URL bereits mit Daten gefüllt ist, da einige URLs ein wenig komplizierter sind als das oben angegebene Beispiel.

Antwort

1

Ich habe dieses Problem ein paar Mal zuvor aufgetreten. Ich habe meine bevorzugte Lösung Schritt für Schritt beschrieben. Die letzten zwei Schritte sind speziell für Ihr Problem in Ihrem Beitrag beschrieben, aber das gleiche Prinzip kann in Ihrer Anwendung (en) angewendet werden.

1. Wurzel Endpunkt

Starten eine Wurzel-Endpunkt auf der API-Ebene durch die Definition. Die entsprechende Root-Entity ist eine Sammlung von Top-Level-Links, also Links, auf die der Client direkten Zugriff benötigt. Die Idee ist, dass der Client nur über einen Endpunkt, nämlich den Wurzelendpunkt, wissen muss. Dies hat den Vorteil, dass Sie die Routing-Logik nicht auf den Client kopieren und, dass die Versionierung der API viel einfacher wird.

Basierend auf Ihrem Beispiel diese Wurzel Endpunkt könnte wie folgt aussehen:

{ 
    "_links": { 
     "products": { 
     "href": "http://localhost:4444/api/products", 
     } 
    } 
} 

2. Zusammenfassung Hauptzustand

Nächstes einen abstrakten Super Zustand definieren, der an der Spitze des Staates Hierarchie befindet.Normalerweise nenne ich diesen Zustand Haupt, um eine Verwechslung mit dem Endpunkt Wurzel zu vermeiden. Die Aufgabe dieses Super-Zustand ist die Wurzel Endpunkt zu lösen, wie:

$stateProvider.state('main', { 
    resolve: { 
     root: function($http) { 
     return $http.get("http://localhost:4444/api/").then(function(resp){ 
       return resp.data; 
     }); 
     } 
    } 
}); 

3. Produktübersicht Zustand als Kind des Hauptstaats

Dann erstellen Sie eine Produkte Zustand, der ein Nachkomme von der ist Hauptzustand. Da die Wurzel Endpunkt bereits behoben ist, können wir es in diesem Zustand benutzen Sie den Link zum Artikel API zu erhalten:

$stateProvider.state('products', { 
    parent: 'main', 
    url: "/products", 
    resolve: { 
     products: function($http, root) { 
     return $http.get(root._links.products.href).then(function(resp){ 
       return resp.data; 
     }); 
     } 
    } 
}); 

4. Produktdetail Zustand als Kind der Produkte Zustand

Schließlich erstellen Produktdetailzustand als Kind des oben genannten Produktstatus. Der Pass in die ID des Produkts über die $stateParams (also es ist Teil des Client-URI) und es verwenden, das richtige Produkt aus dem Produkte Array in der übergeordneten aufgelöst abzurufen:

$stateProvider.state('products.product', { 
    url: "/{productId}" 
    resolve: { 
     product: function($http, $timeout, $state, $stateParams, $q products) { 
     var productId = parseInt($stateParams.productId); 
     var product; 

     for (var i = 0; i < products.length; i++) { 
      product = products[i]; 
      if (product.id === productId) { 
       return $http.get(product._links.self.href).then(function(response){ 
        return response.data; 
       }); 
       } 
     } 

     // go back to parent state if no child was found, do so in a $timeout to prevent infinite state reload 
     $timeout(function(){ 
      $state.go('^', $stateParams); 
     }); 

     // reject the resolve 
     return $q.reject('No product with id ' + productId); 
    } 
}); 

Sie den Code oben in ein bewegen kann Service, um Ihre Staaten leichter zu machen.

Hoffe, das hilft!

Verwandte Themen