wonderful world
wonderful world

Reputation: 11599

How to convert a Fetch API response to RxJS Observable?

How can I convert whatever Fetch API returns to RxJS Observable? Does RxJS.fromPromise help?

Upvotes: 22

Views: 30583

Answers (8)

gwest7
gwest7

Reputation: 1653

With observables it's recommended to make a fetch cancelable:

function fetch$(url:string, options:RequestInit) {
  return new Observable<Response>(subscriber => {
    const controller = new AbortController();
    options.signal = controller.signal;
    fetch(url, options)
    .then(res => {
      subscriber.next(res);
      subscriber.complete();
    })
    .catch(er => subscriber.error(er));
    return () => { // <- return the observable teardown function
      controller.abort();
    }
  })
}

See https://davidwalsh.name/cancel-fetch

Upvotes: 2

zemil
zemil

Reputation: 5090

In my case, I used fromFetch:

import { fromFetch } from 'rxjs/fetch';
import { tap } from 'rxjs/operators';

const fetch$ = <T>(url: string, body: T) => fromFetch(url, {
    method: 'POST',
    mode: 'cors',
    credentials: 'include',
    body: JSON.stringify(body),
    selector: (response) => response.json(),
}).pipe(tap(data => console.log('result:', data)));

fetch$('https://example.com', { somePayload: 123 }).subscribe({
    next: result => console.log(result),
    complete: () => console.log('done')
});

Upvotes: 3

Kuldeep Semwal
Kuldeep Semwal

Reputation: 245

I am using rxjs 6.5.3. I am using below example to convert Fetch API response to RxJS Observable.

const { from } = rxjs;
const { map, switchMap } = rxjs.operators


const observable = from(fetch('data/user.json')).pipe(
    switchMap(response => response.json())
)

observable.subscribe(function(result){
    console.log('result', result);
});

You can also use fromFetch of rxjs. But fetch API are still experimental.

Upvotes: 7

Choco
Choco

Reputation: 1488

Using rxjs 6.4 you can use the from operator

See this link: https://www.learnrxjs.io/operators/creation/from.html

Example is in TS:

public getModelDetails(): Observable<YourType> {

const apiCall = fetch(`yourURL/modelDetails`)
                   .then(response => response.json())
                   .then(responseJson => {
                          return responseJson as YourType
                    })
return from(apiCall)

}

Upvotes: 4

wawka
wawka

Reputation: 5164

As fetch call returns yet another promise containing the response object, I'd go with creating your own observable:

import { Observable } from 'rxjs';

const data$ = Observable.create(observer => {
  fetch('http://server.com')
    .then(response => response.json()) // or text() or blob() etc.
    .then(data => {
      observer.next(data);
      observer.complete();
    })
    .catch(err => observer.error(err));
});

data$.subscribe(data => /*do something with data*/);

Upvotes: 47

Shota Tamura
Shota Tamura

Reputation: 301

I'm using rxjs@6.

The operator that accepts observables(like flatMap, switchMap, etc...) can also accept promise. it's very simple as follows.

somethingObservable.pipe(
    flatMap(() => fetch('http://some.api.com/post/1')),
    subscribe((response) => {
        console.log(response);
    }),
)

Upvotes: 8

sonnenhaft
sonnenhaft

Reputation: 1647

There exist libary rxjs-fetch, but I would suggest not to use it, and write instead:

const getData = (url, params) => {
    return fetch(url, params).then(r => {
        return r.ok ? r.text() : Promise.reject(`${r.statusText} ${r.status}`)
    })
}

const getDataObserver = (url, params) => Rx.Observable.fromPromise(getData())

(in NodeJS you will require node-fetch)

Upvotes: 2

kit
kit

Reputation: 4920

check out this article

var result = Rx.Observable.fromPromise(fetch('http://myserver.com/'));
result.subscribe(x => console.log(x), e => console.error(e));

Upvotes: 15

Related Questions