Skip to content

Commit 8040b42

Browse files
authored
docs: Add section on advanced usage (#11)
1 parent 9fceaf1 commit 8040b42

File tree

1 file changed

+82
-0
lines changed

1 file changed

+82
-0
lines changed

README.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,3 +316,85 @@ expect([...makeIterableHeaders(myHeaders)].length).to.equal(2);
316316
Why are you a weird fellow/gal? Anyway, prejudice aside, body typing will mean nothing to you, so forget about `for()`
317317
and anything else regarding types. Do your custom data-fetching function, add your custom body parsers and fetch away
318318
using `.fetch()`, `.get()`, `head()`, `.post()`, `.put()`, `.patch()` or `.delete()`.
319+
320+
## Plug-ins? Fancy Stuff?
321+
322+
Indeed, we can have fancy stuff. As demonstration, this section will show you how one can add download progress with
323+
a simple class and a custom body parser.
324+
325+
The following is a class for **Svelte v5**. It contains a reactive `progress` property that is updated as download
326+
progresses.
327+
328+
> [!NOTE]
329+
> You should have no problems translating this to Vue, SolidJS or even Angular since all these are signal-powered.
330+
> For React, you'll have to get rid of the signals part and perhaps make it callback-powered.
331+
332+
```ts
333+
export class DownloadProgress {
334+
progress = $state(0);
335+
336+
constructor(response: Response) {
337+
this.#downloadResponse(response);
338+
}
339+
340+
async #downloadResponse(response: Response) {
341+
const totalSize = +(response.headers.get('content-length') ?? 0);
342+
let receivedSize = 0;
343+
const bodyReader = response.body!.getReader();
344+
while (bodyReader) {
345+
const { done, value } = await bodyReader.read();
346+
if (done) {
347+
break;
348+
}
349+
receivedSize += value.length;
350+
this.progress = (receivedSize / totalSize);
351+
}
352+
}
353+
}
354+
```
355+
356+
The class is actually discarding the contents of the downloaded file. Make sure you modify it to save the data. This
357+
example merely cares about illustrating the mechanism of how you can post-process HTTP responses.
358+
359+
### How To Use
360+
361+
Create a custom parser for the content type that will be received, for example, `video/mp4` for MP4 video files.
362+
363+
```ts
364+
// downloader.ts
365+
import { DownloadProgress } from './DownloadProgress.svelte.js';
366+
367+
export default new DrFetch(/* custom fetch function here, if needed */)
368+
.withParser('video/mp4', (r) => Promise.resolve(new DownloadProgress(r)))
369+
;
370+
```
371+
372+
The Svelte component would use this fetcher object. The response from `fetcher.fetch()` (or `fetcher.get()`) will
373+
carry the class instance in the `body` property.
374+
375+
```svelte
376+
<script lang="ts">
377+
import { DownloadProgress } from './DownloadProgress.svelte.js';
378+
import downloader from './downloader.js';
379+
380+
let download = $state<Download>();
381+
382+
async function startDownload() {
383+
download = (await downloader
384+
.for<200, DownloadProgress>()
385+
.get('https://example.com/my-video.mp4'))
386+
.body
387+
;
388+
}
389+
</script>
390+
391+
<button type="button" onclick={startDownload}>
392+
Start Download
393+
</button>
394+
<progress value={download?.progress ?? 0}></progress>
395+
396+
```
397+
398+
When the button is clicked, the download is started. The custom parser simply creates the new instance of the
399+
`DownloadProgress` class. Svelte's reactivity system takes care of the rest, effectively bringing the progress element
400+
to life as the download progresses.

0 commit comments

Comments
 (0)