elbywan / wretch

A tiny wrapper built around fetch with an intuitive syntax. :candy:
MIT License
4.79k stars 96 forks source link

Support stream response #93

Closed ChamNouki closed 3 years ago

ChamNouki commented 3 years ago

With fetch I can do :

fetch('some_url', { headers: { Accept: 'application/stream+json' } })
     .then(response => response.body)
     .then(stream => new Promise(resolve => {
       stream.on('data', data => {
         console.log(new TextDecoder().decode(data));
       });

       stream.on('end', data => {
         console.log(data);
         resolve([]);
       });
     }));

Could be nice to be able to do the same with wretcher ! Something like :

wretcher
    .url('some_url')
    .accept('application/stream+json')
    .get()
.stream()
.on('data', data => {
     console.log(new TextDecoder().decode(data));
})
.on('end', data => {
     console.log(new TextDecoder().decode(data));
})
elbywan commented 3 years ago

Hi @ChamNouki,

Could be nice to be able to do the same with wretcher

This is an interesting idea!

stream.on('data'…

Unfortunately, streams are an advanced use case and usually much more complicated than the example you posted (that has some issues in the way chunks are handled I think).

Also, the syntax you used is very specific to node-fetch, the standard is completely different. wretch should be platform agnostic.

For these reasons, I think it would be better to leave it the way it is. If you want to handle a stream in a generic way, there is the option to simply write a function:

<script type="module">
  import wretch from 'https://unpkg.com/wretch/dist/index.js'

  const chunks = response => new Promise(resolve => {
    const reader = response.body.getReader()
    const chunks = []

    function pump() {
      return reader.read().then(({ done, value }) => {
        if (done) {
          return resolve(chunks)
        }
        chunks.push(value)
        return pump()
      })
    }

    return pump()
  })

  wretch('https://jsonplaceholder.typicode.com/posts/1')
    .get()
    .res(chunks) // <-- here
    .then(console.log) // Array [ Uint8Array(292) ]
</script>
ChamNouki commented 3 years ago

Yeah my idea was clearly an idea to be discussed, and yes my example came from node-fetch ^_^.

My objective working with stream is to be able to use a reactive programming library like RxJS and process result as they arrived from request instead of waiting for the response to be complete and then process an array.

Your exemple seems to be ok but unfortunately does not work as expected on my side. The body property in the response does not contain getReader() methods. Thats why I fall back to fetch.

elbywan commented 3 years ago

Your exemple seems to be ok but unfortunately does not work as expected on my side. The body property in the response does not contain getReader() methods. Thats why I fall back to fetch.

Yes my example was using the browsers apis. You can do the same with node.js using the .on methods.