Lesson 21 / الدرس 21
fetch: talking to a server / fetch: مخاطبة خادم
Asking another machine for data, and the two awaits it always takes. Also the one thing about fetch that everybody gets wrong for the first year: a 404 is not an error.
سؤال آلة أخرى عن بيانات، والانتظاران اللذان يتطلبهما دائمًا. وكذلك الشيء الوحيد الذي يخطئ فيه الجميع في fetch طوال السنة الأولى: أن 404 ليست خطأً.
Two awaits, always
const res = await fetch(url); 1. the headers have arrived
const data = await res.json(); 2. the body has arrived and parsed
res.ok true for 200-299
res.status 404, 500, 201 ...
fetch REJECTS only when the request never happened
- no network, no such host, blocked by CORS
a 404 or a 500 is a successful request with a sad answer:
if (!res.ok) throw new Error('Server said ' + res.status);
Response objects and the code around them is exactly what you write against a real one. Press the 404 button first; it is the whole lesson.
Response حقيقية والشيفرة حولها هي بعينها ما تكتبه مقابل خادم حقيقي. اضغط زر 404 أولًا؛ فهو الدرس كله.Sending, not only asking
const res = await fetch('/api/orders', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ item: 'tea', qty: 2 })
});
// cancelling, and a timeout
const controller = new AbortController();
setTimeout(() => controller.abort(), 5000);
await fetch(url, { signal: controller.signal }); throws AbortError
JSON.stringify is in the middle of it. The Content-Type header is how the server knows to parse it, and without it most servers see an empty body and report a validation error that mentions nothing about headers. And fetch has no timeout at all by default — a request to a server that never answers stays pending for as long as the page is open, which is what AbortController is for. JSON.stringify في وسطه. وترويسة Content-Type هي كيف يعرف الخادم أن يحلله، وبدونها ترى أكثر الخوادم جسمًا فارغًا وتبلّغ بخطأ تحقق لا يذكر الترويسات بشيء. وfetch بلا مهلة البتة افتراضيًا — فالطلب إلى خادم لا يجيب أبدًا يبقى معلّقًا ما دامت الصفحة مفتوحة، ولذلك وُجد AbortController.Access-Control-Allow-Origin. وإن لم يكن خادمك فخياراتك واجهة تسمح بذلك أو نقطة صغيرة على خادمك أنت تقوم بالطلب نيابة عنك. ولا تكن أبدًا إضافة متصفح تعطّل الفحص — فتلك تصلح جهازك ولا تصلح جهاز أحد سواك.| Symptom | Usually |
|---|---|
| TypeError: Failed to fetch | No network, wrong host, or CORS |
| Unexpected token < in JSON | The body was an HTML error page, not JSON |
| Data is undefined | A missing await, or the shape is not what you assumed |
| Works in the console, not in the page | Different origin — the console runs on the page you are viewing |
| 405 or 404 on a POST | The method or the path, not the body |
The second row is the most common message in this entire course, and it almost never means what it says. Print await res.text() instead of res.json() when you meet it: seeing the actual body answers the question in one step.
await res.text() بدل res.json() حين تقابله: فرؤية الجسم الفعلي تجيب السؤال في خطوة واحدة.res.json() بعد res.text() يرمي "دفق الجسم مقروء بالفعل"، وهو محيّر حتى تعرفه. وإن أردت كليهما فخذ النص وحلّله بنفسك — وذلك يعطيك أيضًا الجسم الفعلي لتنظر فيه حين يخفق التحليل، وهي حركة التنقيح من الجدول أعلاه.Try it live / جرّب بنفسك
Check yourself / اختبر نفسك
1.
Does fetch reject when the server answers 404?
fetch حين يجيب الخادم بـ404؟The naive version fails later, at .json(), with a message about JSON and nothing about 404.
.json() برسالة عن JSON ولا شيء عن 404.2. What does "Unexpected token < in JSON" usually mean?
Seeing the actual body answers the question in one step.
3. How do you fix a CORS error?
Never a browser extension that disables the check — that fixes your machine and nobody else's.
Score / النتيجة: 0 / 3
Your task / مهمتك
On your own page, fetch from a real public API and render three fields from the result. Then deliberately produce three failures and record what each one printed: ask for a path that does not exist, turn your network off mid-request, and point the request at a URL that returns HTML. Write the careful version — checking res.ok and throwing with the status — and show that all three now produce a clear message. Add a five-second timeout with AbortController.
على صفحتك أنت، اجلب من واجهة عامة حقيقية واعرض ثلاثة حقول من النتيجة. ثم أنتج ثلاثة إخفاقات عمدًا وسجّل ما طبعه كل واحد: اطلب مسارًا غير موجود، وأطفئ شبكتك أثناء الطلب، ووجّه الطلب إلى عنوان يعيد HTML. واكتب النسخة الحذرة — تفحص res.ok وترمي بالحالة — وأظهر أن الثلاثة تنتج الآن رسالة واضحة. وأضف مهلة خمس ثوانٍ بـAbortController.
- A real API request rendering three fields طلب واجهة حقيقي يعرض ثلاثة حقول
- Three deliberate failures, messages recorded ثلاثة إخفاقات متعمدة برسائلها مسجَّلة
- res.ok checked, with the status in the thrown message res.ok مفحوصة والحالة في الرسالة المرمية
- A five-second timeout that actually aborts مهلة خمس ثوانٍ تُجهض فعلًا