fetchbee
Version:
A lightweight JS library to simplify all kinds of API calls.
194 lines (161 loc) • 6.72 kB
JavaScript
const fallbackBaseUrl = "https://jsonplaceholder.typicode.com/posts";
function createInput(labelText, placeholder = "", type = "text") {
const wrapper = document.createElement("div");
wrapper.style.marginBottom = "12px";
const label = document.createElement("label");
label.textContent = labelText;
label.style.display = "block";
label.style.marginBottom = "4px";
label.style.fontWeight = "bold";
const input = document.createElement("input");
input.placeholder = placeholder;
input.type = type;
input.style.width = "100%";
input.style.padding = "6px";
input.style.border = "1px solid #ccc";
input.style.borderRadius = "4px";
wrapper.appendChild(label);
wrapper.appendChild(input);
return { wrapper, input };
}
function createApiTesterUI() {
const brandColor = "#f1c40f";
document.body.style.fontFamily = "Segoe UI, sans-serif";
document.body.style.margin = "0";
document.body.style.background = "#fff8dc";
const title = document.createElement("h1");
title.textContent = "🐝 FetchBee API Tester";
title.style.color = "#222";
title.style.background = brandColor;
title.style.padding = "16px";
title.style.textAlign = "center";
title.style.margin = "0";
title.style.boxShadow = "0 2px 6px rgba(0,0,0,0.1)";
document.body.prepend(title);
const container = document.createElement("div");
container.style.display = "flex";
container.style.maxWidth = "1100px";
container.style.margin = "30px auto";
container.style.border = `2px solid ${brandColor}`;
container.style.borderRadius = "12px";
container.style.overflow = "hidden";
container.style.boxShadow = "0 0 8px rgba(0,0,0,0.1)";
container.style.gap = "0"; // even spacing
const left = document.createElement("div");
left.style.flex = "3"; // 30%
left.style.padding = "20px";
left.style.background = "#fffef3";
left.style.borderRight = "1px solid #eee";
const right = document.createElement("div");
right.style.flex = "6"; // 60%
right.style.padding = "20px";
right.style.background = "#ffffff";
right.style.overflow = "scroll";
const { wrapper: baseUrlWrap, input: baseUrlInput } = createInput("API Base URL", fallbackBaseUrl);
const { wrapper: idWrap, input: idInput } = createInput("ID (optional)");
const { wrapper: searchWrap, input: searchInput } = createInput("Search (optional)");
const { wrapper: fromWrap, input: fromInput } = createInput("From Date", "", "date");
const { wrapper: toWrap, input: toInput } = createInput("To Date", "", "date");
const { wrapper: pageWrap, input: pageInput } = createInput("Page", "1", "number");
const { wrapper: sizeWrap, input: sizeInput } = createInput("Size", "10", "number");
const { wrapper: tokenWrap, input: tokenInput } = createInput("Auth Token");
[baseUrlWrap, idWrap, searchWrap, fromWrap, toWrap, pageWrap, sizeWrap, tokenWrap].forEach(i => left.appendChild(i));
const bodyLabel = document.createElement("label");
bodyLabel.textContent = "Request Body (for POST / PUT / PATCH)";
bodyLabel.style.fontWeight = "bold";
const bodyInput = document.createElement("textarea");
bodyInput.style.width = "100%";
bodyInput.style.height = "120px";
bodyInput.style.marginTop = "6px";
bodyInput.style.padding = "8px";
bodyInput.style.border = "1px solid #ccc";
bodyInput.style.borderRadius = "4px";
bodyInput.placeholder = `{\n "title": "example",\n "body": "sample",\n "userId": 1\n}`;
right.appendChild(bodyLabel);
right.appendChild(bodyInput);
const buttonGroup = document.createElement("div");
buttonGroup.style.marginTop = "16px";
const errorEl = document.createElement("p");
errorEl.style.color = "red";
const responseEl = document.createElement("pre");
responseEl.style.marginTop = "20px";
responseEl.style.background = "#fdf8e4";
responseEl.style.border = "1px solid #ddd";
responseEl.style.padding = "16px";
responseEl.style.borderRadius = "6px";
responseEl.style.maxHeight = "400px";
responseEl.style.overflow = "auto";
const methods = ["GET", "POST", "PUT", "PATCH", "DELETE"];
methods.forEach((method) => {
const btn = document.createElement("button");
btn.textContent = method;
btn.style.background = brandColor;
btn.style.color = "#000";
btn.style.border = "none";
btn.style.padding = "10px 18px";
btn.style.marginRight = "10px";
btn.style.marginTop = "10px";
btn.style.borderRadius = "4px";
btn.style.cursor = "pointer";
btn.style.fontWeight = "bold";
btn.onclick = async () => {
errorEl.textContent = "";
responseEl.textContent = "⏳ Loading...";
const baseUrl = baseUrlInput.value.trim() || fallbackBaseUrl;
const id = idInput.value.trim();
const url = id ? `${baseUrl}/${id}` : baseUrl;
const query = {};
if (searchInput.value) query.search = searchInput.value.trim();
if (fromInput.value) query.from = fromInput.value;
if (toInput.value) query.to = toInput.value;
if (pageInput.value) query.page = Number(pageInput.value);
if (sizeInput.value) query.size = Number(sizeInput.value);
const headers = {};
if (tokenInput.value.trim()) {
headers.Authorization = `Bearer ${tokenInput.value.trim()}`;
}
let body = {};
if (["POST", "PUT", "PATCH"].includes(method)) {
try {
body = JSON.parse(bodyInput.value || "{}");
} catch (e) {
errorEl.textContent = "Invalid JSON in request body.";
responseEl.textContent = "";
return;
}
}
try {
const response = await fetchBeeRequest(method, url, body, query, headers);
responseEl.textContent = JSON.stringify(response, null, 2);
} catch (err) {
errorEl.textContent = err.message;
responseEl.textContent = "";
}
};
buttonGroup.appendChild(btn);
});
right.appendChild(buttonGroup);
right.appendChild(errorEl);
right.appendChild(responseEl);
container.appendChild(left);
container.appendChild(right);
document.body.appendChild(container);
}
async function fetchBeeRequest(method, url, body = {}, query = {}, headers = {}) {
const queryString = new URLSearchParams(query).toString();
const fullUrl = queryString ? `${url}?${queryString}` : url;
const fetchOptions = {
method,
headers: {
'Content-Type': 'application/json',
...headers,
},
};
if (["POST", "PUT", "PATCH"].includes(method)) {
fetchOptions.body = JSON.stringify(body);
}
const response = await fetch(fullUrl, fetchOptions);
if (!response.ok) throw new Error(`${method} failed with status ${response.status}`);
return await response.json();
}
window.onload = createApiTesterUI;