2017-12-26 14 views
0

Ich muss Entitätsdetails holen, sagen wir Buch von REST-Endpunkt. Das Buch Objekt aussehen könnte diesVerkettung Observablen in eckigen

{ 
    title: XYZ, 
    published: XYZ 
    author: URL_TO_ENDPOINT 
    publisher: URL_TO_ENDPOINT 
} 

Jetzt muß ich Kette Versprechungen, damit ich den Autor und Verleger Daten sowie. Ich habe einfach ApiService die getResourceByURL Methode implementiert, und ich erstellt neuen Service DetailsService, die meine ApiService nennt und Ketten promices Dies ist einfach, solange ich weiß genau, mein Objekt:

return this.apiService.getResourceByURL(book.url).flatMap((entity) => { 
    return Observable.forkJoin(
    Observable.of(entity), 
    this.apiService.getResourceByURL(entity.author) 
    this.apiService.getResourceByURL(entity.publisher) 
).map(entityFullDetails => { 
    let entity = entityFullDetails[0]; 
    let author = entityFullDetails[1]; 
    let publisher = entityFullDetails[2]; 
    entity.author = author; 
    entity.publisher = publisher; 
    return entity; 
    }); 
}); 

Problem ist, dass ich wollte, das verwenden Dieselbe Methode von DetailsService, um auch Details für Autoren/Herausgeber abrufen zu können, was bedeutet, dass es über alle Schlüssel des Entitätsobjekts iterieren müsste und apiService.getResourceByURL aufrufen würde, wenn der Wert dieses Schlüssels eine URL ist (sagen wir mal, es beginnt mit http).

Kann das leicht gemacht werden? oder sollte ich das Abstraktionsniveau senken und separate Methoden vorbereiten, um BookDetail, Autodetail usw. zu erhalten.

Ich bin nur an einer Verschachtelung interessiert. was bedeutet, dass ich von diesem Autor geschrieben nicht brauchen, wenn ich Buch des Autors holen, um alle Bücher zu bekommen es mir gut etwas zu bekommen wie

{ 
    title: XYZ, 
    published: XYZ 
    author: {name: XXX, country: XXX, books: [URL, URL, URL], ...} 
    ... 
} 

zu verhindern bin Bedeutung

+0

Warum sprechen Sie Versprechungen über, wenn Sie nur mit Observablen arbeiten? –

+0

Mögliche Duplikate von [Angular 2 - Chaining http Anfragen] (https://StackOverflow.com/Questions/42626536/angular-2-chaining-http-Requests) –

+0

@ Jota.Toledo Schlagen mich nicht als ein Duplikat, um zumindest nicht zu dieser Frage. OP weiß, wie man Anfragen kettet, es geht nur darum, den Prozess zu automatisieren, ohne die Struktur der zurückgegebenen Ressource kennen zu müssen. –

Antwort

0

Sie Looping eine Funktion nur schreiben kann, die die notwendige tut Dinge automatisch. Es funktioniert tatsächlich rekursiv, aber wenn Sie dies ausdrücklich vermeiden möchten, ersetzen Sie den rekursiven Aufruf einfach durch einen Aufruf an getResourceByURL.

const createFakeResponse = url => { 
 
    switch (url) { 
 
    case 'http://book': return { 
 
     name: 'The rxjs Book', 
 
     author: 'http://author', 
 
     publisher: 'http://publisher', 
 
    }; 
 

 
    case 'http://author': return { 
 
     name: 'John Doe', 
 
     numberOfBooks: 'http://numberOfBooks' 
 
    }; 
 

 
    case 'http://publisher': return 'ACME Publishing Corp.'; 
 
    case 'http://numberOfBooks': return 42; 
 
    } 
 
}; 
 

 
// Fake the HTTP calls with some delay 
 
const getResourceByURL = url => Rx.Observable 
 
    .of(createFakeResponse(url)) 
 
    .do(() => console.log('HTTP call: ', url)) 
 
    .delay(1000 * Math.random()); 
 

 
// Determines whether this key in the resource has to be fetched from its URL 
 
const isReference = ([key, value]) => value.startsWith('http://'); 
 

 
const fetchWithReferences = url => getResourceByURL(url) 
 
    .do(resource => console.log('Raw resource: ', resource)) 
 
    .flatMap(resource => { 
 
     // Find all keys for which the corresponding value is 
 
     // a reference that we need to resolve. 
 
     const referenceKeys = Object.entries(resource) 
 
     .filter(isReference) 
 
     .map(([key]) => key); 
 

 
     return Rx.Observable 
 
     .forkJoin(
 
      Rx.Observable.of(resource), 
 
      ...referenceKeys.map(key => fetchWithReferences(resource[key])) 
 
     ) 
 
     .map(([resource, ...resources]) => Object.assign(resource, ...resources.map((current, index) => { 
 
      // This uses computed property names 
 
      return { [referenceKeys[index]]: current }; 
 
     }))); 
 
    }); 
 

 
console.log('Starting...'); 
 
fetchWithReferences('http://book') 
 
    .map(result => JSON.stringify(result, null, 2)) 
 
    .subscribe(result => console.log('Final result: ', result));
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.min.js"></script>

+0

Danke, sieht aus, als was ich brauche. – Chaki