Skip to content

Instantly share code, notes, and snippets.

@stonetip
Last active April 10, 2024 19:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stonetip/0d7e91465b31e5fc7d17a42276e12486 to your computer and use it in GitHub Desktop.
Save stonetip/0d7e91465b31e5fc7d17a42276e12486 to your computer and use it in GitHub Desktop.
Demonstration of using a Promise within a function (redundant...see fetchLib.js file instead)
// Helper function to determine the appropriate content type and body formatting
function prepareData(data) {
if (data instanceof FormData) {
return { body: data };
}
if (data instanceof Object) {
return {
body: JSON.stringify(data),
headers: { "Content-type": "application/json; charset=UTF-8" }
};
}
return {};
}
// Generalized function to send data with specific HTTP methods
async function sendData(url, method, data) {
try {
const { body, headers } = prepareData(data);
const response = await fetch(url, {
method: method,
body: body,
headers: headers
});
return processFetchResponse(response);
} catch (error) {
console.error("error (internal):", error);
throw error;
}
}
async function getData(url) {
try {
const response = await fetch(url);
return processFetchResponse(response);
} catch (error) {
console.error("error (internal):", error, url);
throw error;
}
}
function postData(url, data) {
return sendData(url, 'POST', data);
}
function putData(url, data) {
return sendData(url, 'PUT', data);
}
function deleteData(url) {
return sendData(url, 'DELETE');
}
// Processing the fetch response based on content type
async function processFetchResponse(response) {
if (!response.ok) {
const errorMsg = await response.text(); // Attempt to read body for detailed error message
throw {
"status": response.status,
"statusText": response.statusText,
"message": errorMsg
};
}
const contentType = response.headers.get("Content-Type") || "";
switch(true) {
case contentType.includes("application/json"):
return response.json();
case contentType.includes("application/octet-stream") || contentType.includes("application/gzip"):
return response.arrayBuffer();
case contentType.includes("text/html"):
const html = await response.text();
return {
page_type: "generic",
html: html
};
default:
throw new Error(`Invalid content type: ${contentType}`);
}
}
function makeCall() {
return new Promise(function (resolve, reject) {
// If the initial call is okay, we'll try processing it.
resolve(
fetch("/myAPI/getData")
.then(response => {
if (!response.ok)
{ throw Error(response) }
return response.json();
})
.then(json => {
console.log(json);
// Note: These are specific to the API being called, not generic results
if (json.exception !== null || json.isFaulted || json.isCanceled) {
throw Error(json);
} else {
// If everything goes alright, let the caller know. (This could contain more info, if necessary)
return "Operation completed.";
}
})
.catch(error => {
console.error(error);
return ("There was an error.");
})
);
// If the initial call was bad, no processing happens
reject(Error("An error occurred."));
}
);
}
window.onload = function () {
const testBtn = document.querySelector("#btnTest");
testBtn.onclick = function () {
makeCall().then(result => console.log(`result: ${result}`));
};
};
@stonetip
Copy link
Author

In the course of working with Fetch, I learned it already is Promise-based. The code above is redundant, so adding adding another gist that has some useful functionality but less wrapping.

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