apex-fetch
v0.1.1
Published
Fast, stable, and configurable fetch layer built on top of native fetch.
Maintainers
Readme
APEX Fetch
[!IMPORTANT] ⚙️ APEX tetap menggunakan mesin fetch native. Library ini tidak mencoba mengganti fondasi runtime, tetapi memperkuat konfigurasi, timeout, retry, hooks, parsing response, dan error handling supaya lebih nyaman dipakai di project nyata.
[!WARNING] 🚫 Paket ini menggunakan lisensi UNLICENSED / All Rights Reserved. Penggunaan, modifikasi, redistribusi, atau pembuatan turunan tanpa izin tertulis dari pemilik hak cipta tidak diperbolehkan.
[!TIP] 🧠 Jika Anda suka kesederhanaan
fetch, tetapi tidak ingin terus-menerus menulis ulang logicbaseURL,timeout,retry,headers, danerror mapping, APEX dibuat untuk kebutuhan itu.
Daftar Isi
- Visi Produk
- Prinsip Desain
- Mengapa APEX
- Fitur Utama
- Instalasi
- Quick Start
- Pola Penggunaan Step by Step
- API Utama
- Lifecycle Request
- Konfigurasi Request
- Tipe Response
- Response Contract
- Error Contract
- Retry Strategy
- Hooks
- Contoh Real Code
- Build dan Validasi
- FAQ
- Legal Notice
Visi Produk
🚀 APEX dirancang sebagai request layer yang terasa ringan saat dipakai, tetapi kuat saat dibutuhkan.
Nama APEX mewakili karakter produk yang ingin dibangun:
- ⚡ Fast
- 🛡️ Stable
- 🎯 Productive
- 😌 Comfortable
- 🎯 Precise
- 🧵 Smooth
- 🧩 Highly configurable
- 🌱 Beginner-friendly
APEX ditujukan untuk developer yang ingin tetap memakai fetch native, tetapi membutuhkan lapisan yang lebih rapi untuk:
- pengelolaan
baseURL - request config yang konsisten
- auto JSON serialization
- response parsing
- retry policy
- timeout dan abort handling
- hook lifecycle
- error contract yang seragam
Dengan kata lain, APEX tidak mengejar abstraksi berlebihan. APEX mengejar request flow yang konsisten, mudah dipahami, dan mudah ditingkatkan saat aplikasi mulai membesar.
Prinsip Desain
🧭 Berikut prinsip desain yang menjadi pondasi APEX:
| Prinsip | Penjelasan |
| ----------------- | --------------------------------------------------------------------------------------------------- |
| Native-first | APEX dibangun di atas fetch, jadi perilaku dasarnya tetap familiar bagi developer web modern. |
| Predictable | Request, response, dan error memiliki kontrak yang konsisten supaya lebih mudah di-debug. |
| Composable | Instance bisa diperluas lewat extend() tanpa perlu menyalin konfigurasi manual berulang kali. |
| Safe defaults | Timeout, retry config, parsing, dan HTTP assertion berjalan dengan default yang masuk akal. |
| Readable DX | API publik dirancang supaya tetap mudah dipakai oleh developer baru maupun tim yang sedang scaling. |
Mengapa APEX
| Kebutuhan | Native fetch | APEX |
| ------------------------- | -------------- | ----------- |
| Request sederhana | Baik | Baik |
| Base URL global | Manual | Built-in |
| Retry | Manual | Built-in |
| Timeout | Manual | Built-in |
| Hook request/response | Manual | Built-in |
| Error contract konsisten | Manual | Built-in |
| DX untuk pemula | Cukup teknis | Lebih ramah |
| Struktur project scalable | Manual | Lebih siap |
[!TIP] 💡 APEX cocok untuk aplikasi frontend, admin dashboard, SPA, SSR ringan, tooling internal, dan service layer yang butuh pola request konsisten.
Cocok untuk siapa
| Tipe pengguna | Alasan |
| ------------------------------- | -------------------------------------------------------------------------- |
| Pemula | Lebih sedikit boilerplate dibanding fetch mentah untuk kebutuhan harian. |
| Frontend developer | Mudah membuat service layer yang konsisten antar endpoint. |
| Team lead | Lebih mudah menjaga standar error handling dan request configuration. |
| Maintainer library internal | Struktur class dan helper membuat codebase lebih gampang diperluas. |
Fitur Utama
| Fitur | Status | Keterangan |
| ---------------- | ------ | ---------------------------------------------------------- |
| createApex() | Siap | Factory utama untuk membuat client |
| HTTP shortcuts | Siap | get, post, put, patch, delete, head, options |
| baseURL | Siap | Menggabungkan base URL dengan path request |
| params | Siap | Query string serialization |
| Auto JSON body | Siap | Plain object dan array di-serialize otomatis |
| Auto JSON parse | Siap | responseType: "auto" mendeteksi JSON |
| timeout | Siap | Berbasis AbortController |
| retry | Siap | Network error, timeout, dan status tertentu |
| Hooks | Siap | onRequest, onResponse, onError |
| Error model | Siap | ApexError dengan code, status, request, response |
| extend() | Siap | Clone instance dengan config baru |
| TypeScript-first | Siap | Type contract konsisten |
🧩 Singkatnya, APEX memberi Anda tiga keuntungan utama sekaligus: kenyamanan konfigurasi, ketahanan request flow, dan kontrak data yang lebih jelas.
Instalasi
📦 Bagian ini menjelaskan cara mulai menggunakan APEX dengan cepat dan benar.
1. Install package
npm install apex-fetch2. Pastikan runtime mendukung fetch
APEX dirancang untuk:
- Browser modern
- Node.js 18+
3. Import dari package
import { createApex } from "apex-fetch";[!INFO] ℹ️ Jika Anda berada di Node.js lama yang belum menyediakan
fetchnative, Anda perlu menyediakan implementasifetchsendiri melalui konfigurasifetch.
4. Tentukan gaya pemakaian Anda
APEX bisa dipakai dalam dua pola utama:
- langsung di komponen atau action untuk kebutuhan cepat
- melalui service layer untuk project yang lebih rapi dan scalable
Quick Start
import { createApex } from "apex-fetch";
const api = createApex({
baseURL: "https://api.example.com",
timeout: 10000,
retry: {
limit: 2,
},
});
const res = await api.get<{ id: number; name: string }>("/users/1");
console.log(res.data);
console.log(res.status);Apa yang terjadi pada contoh di atas
- 🌐
baseURLmembuat endpoint relatif menjadi lebih pendek dan konsisten - ⏱️
timeoutmelindungi request agar tidak menggantung terlalu lama - 🔁
retry.limitmemberi kesempatan request pulih dari gangguan sementara - 📦
res.datamemberi payload hasil parsing tanpa membuat Anda kehilangan akses ke metadata response
Jika Anda baru mulai, contoh ini sudah cukup untuk membangun request layer yang sehat sejak awal.
Pola Penggunaan Step by Step
🪜 Di bawah ini adalah urutan pemakaian yang paling mudah dipahami dari nol sampai siap dipakai di project nyata.
Step 1 — Buat client utama
import { createApex } from "apex-fetch";
const api = createApex({
baseURL: "https://api.example.com",
});Step 2 — Tambahkan konfigurasi dasar
const api = createApex({
baseURL: "https://api.example.com",
timeout: 8000,
headers: {
Accept: "application/json",
},
});Step 3 — Kirim request GET
const res = await api.get<{ items: string[] }>("/items");
console.log(res.data.items);Step 4 — Kirim request dengan query params
const res = await api.get("/search", {
params: {
page: 1,
keyword: "apex",
tag: ["fetch", "typescript"],
},
});Step 5 — Kirim request POST JSON
const res = await api.post("/users", {
name: "Fauzan",
role: "admin",
});Step 6 — Tangani error dengan aman
import { isApexError } from "apex-fetch";
try {
await api.get("/private");
} catch (err) {
if (isApexError(err)) {
console.error(err.code);
console.error(err.status);
}
}Ringkasan hasil akhir
Setelah enam langkah di atas, Anda sudah punya fondasi request layer yang:
- lebih konsisten daripada
fetchmentah - lebih aman terhadap timeout dan error umum
- lebih gampang dipakai ulang di berbagai file atau service
API Utama
🧱 API publik APEX sengaja dibuat ringkas agar mudah diingat, tetapi tetap cukup kuat untuk kebutuhan proyek yang serius.
Factory
| API | Deskripsi |
| --------------------- | -------------------------- |
| createApex(config?) | Membuat instance APEX baru |
Client Methods
| Method | Deskripsi |
| ---------------------------- | --------------------------- |
| request(config) | Jalur paling fleksibel |
| get(url, config?) | Request GET |
| post(url, body?, config?) | Request POST |
| put(url, body?, config?) | Request PUT |
| patch(url, body?, config?) | Request PATCH |
| delete(url, config?) | Request DELETE |
| head(url, config?) | Request HEAD |
| options(url, config?) | Request OPTIONS |
| extend(config?) | Membuat turunan client baru |
Error Utilities
| Utility | Deskripsi |
| -------------------- | ---------------------------------------- |
| ApexError | Error class utama APEX |
| isApexError(value) | Type guard untuk identifikasi error APEX |
Catatan penting tentang extend()
extend() sangat berguna saat Anda ingin membuat client turunan tanpa mengulang seluruh konfigurasi. Pola ini sangat cocok untuk:
- client authenticated
- client admin
- client per-module
- client per-tenant
Lifecycle Request
🔄 Secara garis besar, alur internal APEX berjalan seperti ini:
| Tahap | Deskripsi |
| ----------------------- | ---------------------------------------------------------------------------------- |
| 1. merge config | Config instance dan config request digabung lebih dulu. |
| 2. resolve request | Default config dirapikan menjadi bentuk final yang siap dipakai. |
| 3. build URL | baseURL dan params disusun menjadi URL final. |
| 4. build body | Body diproses dan header seperti content-type disesuaikan. |
| 5. run request hooks | Semua onRequest dijalankan sebelum request dikirim. |
| 6. send fetch | Request dikirim memakai fetch yang aktif. |
| 7. evaluate retry | APEX memutuskan apakah perlu retry berdasarkan error atau status response. |
| 8. parse response | Response diubah menjadi data sesuai responseType. |
| 9. run response hooks | Semua onResponse dijalankan setelah parsing selesai. |
| 10. assert HTTP | Jika throwOnHTTPError aktif, status 4xx/5xx akan dilempar sebagai ApexError. |
| 11. run error hooks | Jika flow gagal, onError dijalankan sebelum error dilempar keluar. |
Lifecycle ini penting karena membantu Anda memahami di mana sebuah error muncul, kapan hook dieksekusi, dan mengapa retry bisa terjadi.
Konfigurasi Request
⚙️ Semua method APEX pada akhirnya bermuara ke ApexRequestConfig. Memahami objek ini berarti memahami hampir seluruh kekuatan library.
| Opsi | Tipe | Default | Keterangan |
| ------------------ | --------------------- | -------------- | -------------------------------- |
| url | string | "" | Path atau URL absolut |
| method | string | "GET" | HTTP method |
| baseURL | string | undefined | Prefix URL |
| headers | HeadersInit | {} | Header request |
| params | Record<string, ...> | undefined | Query params |
| body | unknown | undefined | Body request |
| timeout | number | 0 | Timeout dalam ms |
| retry | number \| object | 0 | Retry policy |
| responseType | "auto" \| ... | "auto" | Mode parsing response |
| parseJson | boolean | true | Mengaktifkan parse JSON otomatis |
| throwOnHTTPError | boolean | true | Lempar error saat 4xx/5xx |
| credentials | RequestCredentials | undefined | Credential mode |
| signal | AbortSignal | undefined | External abort signal |
| fetch | typeof fetch | native fetch | Override fetch implementation |
| hooks | Partial<ApexHooks> | kosong | Hook lifecycle |
Cara membaca config ini
baseURL+urlmembentuk alamat akhir requestparamsdiubah menjadi query stringbodyakan di-serialize otomatis jika berupa object atau array biasatimeoutbekerja lewatAbortControllerretrybisa berupa angka singkat atau object detailresponseTypemenentukan bagaimana response diparse
Tipe Response
🧪 APEX mendukung beberapa mode parsing supaya Anda bisa menyesuaikan output dengan kebutuhan endpoint.
| responseType | Hasil | Kapan dipakai |
| --------------- | ---------------------------------------------------------------------- | ------------------------------------------------ |
| "auto" | Menebak JSON bila memungkinkan, selain itu mengikuti fallback internal | Cocok untuk sebagian besar API JSON modern |
| "json" | Memaksa parse JSON | Saat endpoint dipastikan selalu JSON |
| "text" | Mengembalikan string | Untuk health check, plain text, atau HTML ringan |
| "blob" | Mengembalikan Blob | Cocok untuk browser file preview atau download |
| "arrayBuffer" | Mengembalikan ArrayBuffer | Untuk binary processing |
| "formData" | Mengembalikan FormData | Untuk endpoint yang memang merespons form-data |
| "raw" | Mengembalikan objek Response sebagai data | Saat Anda butuh kontrol manual penuh |
[!TIP] 🎯 Jika Anda tidak punya kebutuhan khusus, gunakan
responseType: "auto"karena itu adalah mode yang paling nyaman untuk mayoritas kasus API JSON.
Response Contract
APEX mengembalikan wrapper response yang konsisten.
type ApexResponse<T> = {
data: T;
status: number;
statusText: string;
headers: Headers;
url: string;
ok: boolean;
raw: Response;
};Keuntungan pendekatan ini
- 🔍 lebih informatif
- 🛠️ lebih mudah di-debug
- 📈 siap untuk scaling
- 📬 tidak memaksa developer kehilangan akses ke
statusdanheaders
Kenapa tidak langsung mengembalikan body saja
Karena di dunia nyata, developer sering tetap membutuhkan:
- status code untuk branching logic
- headers untuk pagination, token refresh, atau metadata
- raw response untuk kasus lanjutan
Dengan kontrak response seperti ini, APEX menjaga payload tetap nyaman diakses tanpa membuang konteks penting.
Error Contract
🧯 APEX menggunakan class ApexError dengan struktur yang seragam supaya penanganan error tidak liar antar endpoint.
| Code | Arti |
| ------------------ | ------------------------------ |
| ERR_APEX_NETWORK | Gagal network request |
| ERR_APEX_TIMEOUT | Request melebihi batas timeout |
| ERR_APEX_ABORTED | Request dibatalkan |
| ERR_APEX_HTTP | HTTP response tidak ok |
| ERR_APEX_PARSE | Gagal parse response |
| ERR_APEX_CONFIG | Konfigurasi tidak valid |
| ERR_APEX_UNKNOWN | Error tidak dikenal |
Cara membaca ApexError
Biasanya Anda akan memeriksa beberapa properti ini:
error.codeuntuk klasifikasi masalaherror.statusuntuk HTTP failureerror.requestuntuk melihat config final yang dipakaierror.responseuntuk memeriksa metadata response jika tersedia
Contoh penanganan error
import { createApex, isApexError } from "apex-fetch";
const api = createApex({
baseURL: "https://api.example.com",
});
try {
await api.get("/reports");
} catch (err) {
if (isApexError(err)) {
console.error(err.code);
console.error(err.status);
console.error(err.request);
}
}Retry Strategy
🔁 APEX mendukung retry sederhana maupun detail. Tujuannya bukan membuat semua request diulang tanpa aturan, tetapi memberikan kebijakan retry yang eksplisit dan terkontrol.
Bentuk singkat
const api = createApex({
retry: 2,
});Bentuk detail
const api = createApex({
retry: {
limit: 3,
delay: 300,
backoff: "exponential",
retryOnTimeout: true,
retryOnNetworkError: true,
retryOnStatuses: [408, 429, 500, 502, 503, 504],
},
});Backoff yang didukung
| Mode | Perilaku |
| ------------- | ---------------------------- |
| static | Delay tetap |
| linear | Delay bertambah linear |
| exponential | Delay bertambah eksponensial |
[!TIP] 🛡️ Untuk endpoint idempoten seperti
GET, retry sangat cocok. Untuk request tertentu yang membawa stream sekali pakai, replay mungkin tidak aman.
Kapan retry sebaiknya dipakai
- ya untuk
GET, status sementara seperti503, dan gangguan jaringan ringan - hati-hati untuk request dengan side effect
- hindari jika body tidak aman untuk dikirim ulang
Hooks
🪝 APEX menyediakan tiga jenis hook utama untuk observability, enrichment, dan error handling.
| Hook | Waktu berjalan |
| ------------ | ------------------------------------- |
| onRequest | Sebelum request dikirim |
| onResponse | Setelah response diterima dan diparse |
| onError | Saat flow request gagal |
Kegunaan hook di dunia nyata
onRequestuntuk menambah header, tracing, atau audit metadataonResponseuntuk logging status, analytics, atau transform lanjutan di level observasionErroruntuk pelaporan error, toast, Sentry bridge, atau metric internal
Contoh hook global
const api = createApex({
hooks: {
onRequest: [
({ request }) => {
request.headers.set("x-client", "apex");
},
],
onResponse: [
({ response }) => {
console.log("status:", response.status);
},
],
onError: [
({ error }) => {
console.error("apex error:", error.code);
},
],
},
});Contoh Real Code
1. Service layer untuk aplikasi dashboard
import { createApex } from "apex-fetch";
const api = createApex({
baseURL: "https://api.example.com",
timeout: 10000,
headers: {
Accept: "application/json",
},
retry: {
limit: 2,
delay: 250,
backoff: "exponential",
},
});
export async function getUsers() {
const res = await api.get<{ id: number; name: string }[]>("/users");
return res.data;
}
export async function createUser(data: { name: string; role: string }) {
const res = await api.post<{ id: number; name: string }>("/users", data);
return res.data;
}2. Client turunan untuk endpoint authenticated
import { createApex } from "apex-fetch";
const api = createApex({
baseURL: "https://api.example.com",
});
export function makeAuthApi(token: string) {
return api.extend({
headers: {
Authorization: `Bearer ${token}`,
},
});
}3. Request dengan response text
const api = createApex({
baseURL: "https://api.example.com",
});
const res = await api.get<string>("/health", {
responseType: "text",
throwOnHTTPError: false,
});
console.log(res.data);4. Penggunaan custom fetch
import { createApex } from "apex-fetch";
const api = createApex({
fetch: globalThis.fetch,
});Build dan Validasi
🧪 Sebelum APEX dipakai lebih jauh, project sudah divalidasi lewat type check, test suite, dan build output.
Perintah yang tersedia:
npm run check
npm run test
npm run buildStatus validasi saat ini
| Validation | Status | | ------------ | ---------------- | | Type check | Lulus | | Test suite | Lulus | | Timeout test | Sudah diperbaiki | | Retry test | Lulus | | Hook test | Lulus |
FAQ
Apakah APEX menggantikan fetch native?
Tidak. 🙂 APEX justru dibangun di atas fetch native. Tujuannya adalah memberi lapisan ergonomis dan stabil, bukan menciptakan runtime baru.
Kapan saya sebaiknya memakai createApex() satu kali lalu extend()?
Saat project punya banyak domain API atau banyak variasi auth. Dengan pola ini, Anda bisa punya satu base client lalu membuat turunan yang lebih spesifik untuk tiap kebutuhan.
Apakah APEX cocok untuk project kecil?
Cocok. 🌱 Untuk project kecil, manfaat terbesarnya adalah pengurangan boilerplate. Untuk project besar, manfaat terbesarnya adalah konsistensi dan skalabilitas.
Apakah saya masih bisa memakai fetch custom?
Bisa. 🔌 Anda dapat mengisi properti fetch di config jika ingin memakai implementasi fetch lain yang kompatibel.
Kapan saya harus memakai responseType: "raw"?
Gunakan saat Anda ingin memegang Response secara manual, misalnya untuk kebutuhan parsing khusus, stream handling, atau kontrol header yang lebih eksplisit.
Kenapa response APEX tidak langsung hanya data?
Karena dalam aplikasi nyata, status, headers, ok, dan raw response sering tetap dibutuhkan. APEX menjaga keseimbangan antara kemudahan akses payload dan kelengkapan metadata. 📬
Legal Notice
[!WARNING] ⚖️ APEX Fetch tidak dirilis dengan lisensi open-source. Keberadaan package di registry publik tidak berarti source code boleh digunakan, dimodifikasi, atau didistribusikan ulang secara bebas.
Ringkasan legal
- 🚫 Tidak boleh menyalin source tanpa izin
- 🚫 Tidak boleh memodifikasi atau membuat turunan tanpa izin
- 🚫 Tidak boleh mendistribusikan ulang tanpa izin
- 🚫 Tidak boleh menjual, membundel ulang, atau white-label tanpa izin
Silakan baca file LICENSE untuk ketentuan lengkap.
Penutup
🏁 APEX Fetch dirancang untuk developer yang menginginkan lapisan fetch yang:
- cepat
- stabil
- presisi
- mudah di-setup
- nyaman untuk dipakai harian
- cukup fleksibel untuk project yang berkembang
Jika tujuan Anda adalah membuat request layer yang bersih, konsisten, mudah dipahami, dan siap tumbuh bersama project, maka APEX adalah fondasi yang tepat. ✨
