Skip to content

Instantly share code, notes, and snippets.

@whiteinge
Last active March 8, 2025 06:30
Show Gist options
  • Save whiteinge/f296e3ddb722a5c8763e89ab2e4440a1 to your computer and use it in GitHub Desktop.
Save whiteinge/f296e3ddb722a5c8763e89ab2e4440a1 to your computer and use it in GitHub Desktop.
Utility functions that fit the Fetch ecosystem API philosophy
/**
Create a file-like object suitable for use with the fetch() API ecosystem
fetch('/some/path', { method: 'POST', body: tojson({foo: 'Foo!'}) });
// Sets the content-type of the request automatically:
const req = new Request('/some/path', {
mode: 'cors',
headers: { 'Accept': 'application/json' },
body: tojson({ foo: 'Foo!' }),
});
// => req.headers.get('content-type') === 'application/json'
**/
export const tojson = (data) =>
new Blob([JSON.stringify(data)], { type: 'application/json' });
/**
Return the response body appropriate to the content-type
fetch(...).then((rep) => rep.then(getBody).then((body) => ({
success: rep.ok ? body : null,
error: !rep.ok
? (!isEmpty(body)
? body
: `${rep.status}: ${rep.statusText}`)
: null,
type: rep.headers.get('content-type'),
})))
**/
export const getBody = (rep) => {
const clen = rep.headers.get('content-length');
if (clen === 0 || clen == null) {
return Promise.resolve(null);
}
const ctype = rep.headers.get('content-type').split(';').at(0).trim();
switch (ctype) {
case 'application/json':
return rep.json();
case 'text/html':
case 'text/xml':
case 'image/svg+xml':
return rep.text()
.then((x) => new window.DOMParser().parseFromString(x, ctype));
case 'text/csv':
case 'text/plain':
return rep.text();
case 'multipart/form-data':
return rep.formData();
case 'text/event-stream':
return rep.blob().then((x) => x.stream());
default:
return rep.blob();
}
};
@whiteinge
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment