جافاسكربتFetch API
- ما هو Fetch API
- كيفية استخدام Fetch API
- تحديد طريقة إرسال الطلب في Fetch API
- تحديد نوع الطلب أو الرد في Fetch API
- أساليب عرض نتائج طلبات Fetch API
- معالجة الأخطاء في Fetch API
- أمثلة شاملة على استخدام Fetch API
ما هو Fetch API
Fetch API هو أحدث آلية تم إضافتها في جافاسكربت لجعل صفحات الويب قادرة على إرسال طلبات المستخدم ( User Requests ) و استقبال ردود السيرفر ( Server Responses ) بشكل متزامن و بدون الحاجة إلى تحديث الصفحة أو الإنتقال لصفحة جديدة.
إرسال الطلبات بشكل متزامن إلى السيرفر تحتاجه في حالات كثيرة نذكر منها:
- لجعل المستخدم قادر على إضافة تعليق جديد.
- لجعل المستخدم قادر على جلب التعليقات و عرضها له.
- لجعل المستخدم قادر على تقييم محتوى الصفحة.
- لجعل المستخدم قادر على رفع صورة و ضبط حجمها إلخ..
في هذا الدرس ستتعلم كيفية إرسال طلبات متزامنة إلى السيرفر عن طريق Fetch API خطوة خطوة.
قبل وجود Fetch API كانت طريقة إرسال و استقبال البيانات بشكل متزامن تتم من خلال استخدام آلية XMLHttpRequest و التي كان استخدامها أصعب و غالباً ما كان مطوروا الويب يلجؤوا الى استخدام مكتبة JQuery التي كانت تجعل هذا الأمر سهل للغاية.
كيفية استخدام Fetch API
بدايةً، عليك معرفة أن Fetch API مبني بأسلوب البرومس ( Promise ) مما يعني أنه عند إرسال الطلبات بواسطته فإنه يتم إرسالها بشكل متزامن و النتيجة التي ترجع قد تكون نتيجة صحيحة و قد تكون نتيجة مرفوضة بالإضافة إلى أنه قد يحدث مشكلة أثناء التنفيذ.
التعامل مع Fetch API يتم من خلال الدالة fetch()
المبنية على النحو التالي.
fetch(resource, options)
- مكان البارميتر
resource
نمرر المصدر أو الرابط الذي سيتم إرسال الطلب إليه. options
هو باراميتر إختياري - على حسب نوع الطلب - و مكانه يمكن تمرير كائن فيه معلومات مرتبطة بالطلب.
بما أن الدالة fetch()
عبارة عن برومس فإنه يجب استدعاء الدالة then()
منها أو وضع الكلمة await
قبلها حتى تتنفذ.
سنشرح كلا الأسلوبين و لكننا سنركز على أسلوب async / await
لأنه أكثر سهولة في التعامل.
كمثال بسيط، هكذا يكون شكل الطلب الذي يعطينا الصفحة الرئيسية في موقع هرمش.
المثال الأول
fetch("https://harmash.com")
تحديد طريقة إرسال الطلب في Fetch API
كل طلب يتم إرساله إلى السيرفر يتم إرساله بطريقة محددة ( method
) من الطرق المذكورة في الجدول التالي.
الطريقة | إستعمالها |
---|---|
GET |
هذه الطريقة الإفتراضية في إرسال الطلبات و هي تستعمل لإرسال طلب عام، مثل طلب إحضار صفحة من الموقع. |
POST |
هذا الطريقة تستعمل لإرسال طلب خاص، مثل طلب تسجيل دخول في الموقع. |
PUT |
هذا الطريقة تستعمل لإرسال طلب لتعديل كلي، مثل طلب تعديل كل معلومات المستخدم. |
PATCH |
هذا الطريقة تستعمل لإرسال طلب تعديل جزئي، مثل طلب تعديل بعض معلومات المستخدم. |
DELETE |
هذا الطريقة تستعمل لإرسال طلب للحذف، مثل طلب لحذف مستخدم. |
على الرغم من أن طرق إرسال الطلبات تحدد ما يقوم به الطلب بدقة إلا أنه عادةً ما يستعمل المطورون الطريقة GET
و POST
فقط.
فعلياً، هكذا يكون شكل الطلب الذي يعطينا الصفحة الرئيسية في موقع هرمش.
المثال الأول
fetch("https://harmash.com", { method: 'GET', })
و هكذا يكون شكل الطلب الذي يسمح لنا بحذف مقال من موقع هرمش.
المثال الثاني
fetch("https://harmash.com/posts/1", { method: 'DELETE', })
تحديد نوع الطلب أو الرد في Fetch API
الطلبات التي يتم إرسالها للسيرفر أو الردود التي تأتي منه يجب أن يتم تحديد أنواعها ( Content-type
) بشكل صحيح حتى يتم نقلها بشكل صحيح.
الجدول التالي يتضمن أنواع الطلبات و الردود التي يجب معرفتها.
نوع الرد | معناه |
---|---|
text/plain |
هذا هو نوع الرد الإفتراضي و معناه أن الرد سيتم إستلامه على شكل نص عادي. |
text/html |
هذا النوع من الرد معناه أن الرد سيتم إستلامه على شكل نص و لكنه بلغة HTML. |
text/css |
هذا النوع من الرد معناه أن الرد سيتم إستلامه على شكل نص و لكنه بلغة CSS. |
text/xml |
هذا النوع من الرد معناه أن الرد سيتم إستلامه على شكل نص و لكنه بلغة XML. |
text/csv |
هذا النوع من الرد معناه أن الرد سيتم إستلامه على شكل نص و لكنه بلغة CSV. |
text/javascript |
هذا النوع من الرد معناه أن الرد سيتم إستلامه على شكل نص و لكنه بلغة JavaScript. |
application/json |
هذا النوع من الرد معناه أن الرد سيتم إستلامه على شكل نص و لكنه بأسلوب JSON. |
image/png |
هذا النوع من الرد معناه أن الرد سيتم إستلامه على شكل صورة نوعها PNG. |
image/apng |
هذا النوع من الرد معناه أن الرد سيتم إستلامه على شكل صورة نوعها APNG. |
image/gif |
هذا النوع من الرد معناه أن الرد سيتم إستلامه على شكل صورة نوعها GIF. |
image/jpeg |
هذا النوع من الرد معناه أن الرد سيتم إستلامه على شكل صورة نوعها JPEG. |
image/svg+xml |
هذا النوع من الرد معناه أن الرد سيتم إستلامه على شكل صورة نوعها SVG. |
image/webp |
هذا النوع من الرد معناه أن الرد سيتم إستلامه على شكل صورة نوعها WEBP. |
application/octet-stream |
هذا النوع من الرد معناه أن الرد سيتم إستلامه على شكل Binary و هذا النوع لا يمكن عرضه في الصفحة، مما يجعل المستخدم قادر على حفظ هذا الرد كملف على جهازه. |
multipart/form-data |
هذا النوع يستعمل عند إرسال بيانات النموذج و التي قد تتضمن ملف أو صورة مرفقة معها. |
كمثال بسيط، هكذا يكون شكل الطلب الذي يسمح لنا بتسجيل الدخول في موقع هرمش.
لاحظ أن الطريقة التي استخدمناه في إرسال الطلب للسرفر هي POST
و سيتم ترتيب البيانات في الطلب بأسلوب JSON
مثال
fetch("https://harmash.com/account/login", { method: 'POST', headers: { 'Content-type': 'application/json', }, body: JSON.stringify({ username: 'test', password: '1234', } })
أساليب عرض نتائج طلبات Fetch API
في المثال التالي قمنا بجلب ملف نصي إسمه demo.txt
موجود في هرمش، و من ثم قمنا بتحويل محتواه لنص عادي بواسطة الدالة text()
و في النهاية قمنا بعرضه في الصفحة على أنه محتوى HTML.
مثال
// وضعنا فيه مسار الملف الذي سنقوم بطلبه url المتغير let url = 'https://harmash.com/tutorials/javascript/fetch-api/demo.txt'; // هنا قمنا بإرسال طلب لإحضار الملف و من ثم عرض نتيجته في الصفحة fetch(url) .then(response => response.text()) .then(data => document.write(data));
المثال السابق نفسه يمكن كتابته بأسلوب async / await
على النحو التالي.
مثال
// fetchData كود جلب إرسال الطلب وضعناه كله بداخل دالة إسمها async function fetchData() { // وضعنا فيه مسار الملف الذي سنقوم بطلبه url المتغير let url = 'https://harmash.com/tutorials/javascript/fetch-api/demo.txt'; // response هنا قمنا بإرسال طلب لإحضار الملف مع تخزين النتيجة في المتغير let response = await fetch(url); // data إلى نص و تخزينها في المتغير response هنا قمنا بتحويل النتيجة الموجودة في المتغير let data = await response.text(); // في الصفحة data هنا قمنا بعرض النص الموجود في المتغير document.write(data); } // حتى تتنفذ fetchData() هنا قمنا باستدعاء الدالة fetchData();
معالجة الأخطاء في Fetch API
عند طلب بيانات من أي سيرفر فإنه قد يعرض لك نتيجة مرفوضة ( Rejected ) أو قد يحدث خطأ ( Error ) ما أثناء تنفيذ الطلب.
نتيجة الطلب تعتبر مقبولة ( Resolved ) إذا كانت حالة التنفيذ المرفقة في رد السيرفر هي 200
أو ببساطة هي ok
.
غير ذلك تعتبر فإن نتيجة تعتبر غير مقبولة و هنا فإننا في الواقع نظهرها كخطأ للمستخدم.
إذاً بناءاُ على رد السيرفر يمكنك معرفة ما إن كانت القيمة مقبولة أم لا.
في الأمثلة التالية، مسار الملف الذي سنحاول جلبه كتبناه بشكل خاطئ عمداً حتى نتسبب بخطأ.
عند تجربة الأمثلة فإنه عليك الإنتظار لبضعة ثواني ريثما يظهر لك أنه يوجد خطأ.
إذا كنت تستخدم الدالة then()
فيمكنك إضافة الدالة catch()
في النهاية لمعالجة أي خطأ يحدث.
مثال
// وضعنا فيه مسار الملف الذي سنقوم بطلبه و الذي نعلم أنه مكتوب بشكل خاطئ url المتغير let url = 'https://wrong-path-name/demo.txt'; // هنا قمنا بإرسال طلب لإحضار الملف و من ثم عرض نتيجته في الصفحة fetch(url) .then(response => { // هنا قمنا بفحص الرد الذي أتى من السيرفر لمعرفة ما إن كان قد رد بقيمة مقبولة أم لا if (!response.ok) { // إذا كان قد رد بقيمة غير مقبولة، سيتم عرض النص التالي كخطأ وقع عند التنفيذ throw new Error('Response was not ok'); } // إذا كان الرد مقبولاً فسيتم تحويله إلى نص ليتم عرضه من بعدها return response.text(); }) .then(data => document.write(data)) .catch(error => document.write(error));
إذا كنت تستخدم async / await
فيمكنك وضع الكود بداخل بلوك try / catch
لمعالجة أي خطأ قد يحدث أثناء تنفيذ الكود.
مثال
async function fetchData() { try { // وضعنا فيه مسار الملف الذي سنقوم بطلبه و الذي نعلم أنه مكتوب بشكل خاطئ url المتغير let url = 'https://wrong-path-name/demo.txt'; // response هنا قمنا بإرسال طلب لإحضار الملف مع تخزين النتيجة في المتغير let response = await fetch(url); // هنا قمنا بفحص الرد الذي أتى من السيرفر لمعرفة ما إن كان قد رد بقيمة مقبولة أم لا if (!response.ok) { // إذا كان قد رد بقيمة غير مقبولة، سيتم عرض النص التالي كخطأ وقع عند التنفيذ throw new Error('Response was not ok'); } // data إلى نص و تخزينها في المتغير response هنا قمنا بتحويل النتيجة الموجودة في المتغير let data = await response.text(); // في الصفحة data هنا قمنا بعرض النص الموجود في المتغير document.write(data); } catch (error) { // إذا حصل أي خطأ، سيتم طباعته في الصفحة document.write(error); } } // حتى تتنفذ fetchData() هنا قمنا باستدعاء الدالة fetchData();
أمثلة شاملة على استخدام Fetch API
سنطبق جميع الأمثلة التالية على API وهمي مجاني تابع لموقع typicode.com.
في المثال التالي قمنا بطلب مقال واحد من الموقع و من ثم قمنا بعرض محتواه في الصفحة.
المثال الأول
// هنا قمنا بتعريف دالة تقوم بإرسال طلب إلى السيرفر بشكل متزامن و من ثم تعرض نتيجته async function fetchData() { // وضعنا فيه مسار الموقع الذي سنقوم بإرسال الطلب إليه url المتغير let url = 'https://jsonplaceholder.typicode.com/posts/1'; try { // url هنا قمنا بإرسال طلب إلى الرابط الموجود في let response = await fetch(url); // هنا قمنا بفحص الرد الذي أتى من السيرفر لمعرفة ما إن كان قد تم العثور على المقال بنجاح أم لا if (!response.ok) { // إذا كان رد السيرفر يفيد بأن قد فشل في جلبه فسيتم // عرض النص التالي للإشارة إلى وقوع خطأ عند التنفيذ throw new Error('Network response was not ok'); } // إلى كائن جافاسكربت JSON إذا كان الرد مقبولاً فسيتم تحويله من صيغة let data = await response.json(); // بعد أن تم تحويل الرد إلى كائن، سيتم عرض القيم الموجودة فيه document.write(` <p>Fetched data:</p> <ul> <li>userId: ${data.userId}</li> <li>id: ${data.id}</li> <li>title: ${data.title}</li> <li>body: ${data.body}</li> </ul>`); } catch(error) { // إذا حصل أي خطأ أثناء جلب البيانات سيتم عرضه alert(error); } } // حتى تتنفذ fetchData() هنا قمنا باستدعاء الدالة fetchData();
قمنا بكتابة response.json()
لأجل إرجاع الكائن الذي وصلنا عند تنفيذ الطلب على هيئة JSON إلى كائن جافاسكربت.
في المثال التالي قمنا بطلب جميع المقالات من الموقع و من ثم قمنا بعرض محتواه في الصفحة.
ملاحظة: سيتم إحضار مئة مقال، سنعرض من كل مقال عنوانه و الفقرة الموجودة فيه.
المثال الثاني
// هنا قمنا بتعريف دالة تقوم بإرسال طلب إلى السيرفر بشكل متزامن و من ثم تعرض نتيجته async function fetchData() { // وضعنا فيه مسار الموقع الذي سنقوم بإرسال الطلب إليه url المتغير let url = 'https://jsonplaceholder.typicode.com/posts'; try { // url هنا قمنا بإرسال طلب إلى الرابط الموجود في let response = await fetch(url); // هنا قمنا بفحص الرد الذي أتى من السيرفر لمعرفة ما إن كان قد تم العثور على المقالات بنجاح أم لا if (!response.ok) { // إذا كان رد السيرفر يفيد بأن قد فشل في جلبهم فسيتم // عرض النص التالي للإشارة إلى وقوع خطأ عند التنفيذ throw new Error('Network response was not ok'); } // إلى مصفوفات كائنات جافاسكربت JSON إذا كان الرد مقبولاً فسيتم تحويله من صيغة let data = await response.json(); // بعد أن تم تحويل الرد إلى مصفوفة كائنات، سيتم المرور عليهم جميعاً و عرض بعض قيمهم for(x of data) { document.write(` <h3>${x.title}</h3> <p>${x.body}</p> <hr>`); } } catch(error) { // إذا حصل أي خطأ أثناء جلب البيانات سيتم عرضه alert(error); } } // حتى تتنفذ fetchData() هنا قمنا باستدعاء الدالة fetchData();
في المثال التالي قمنا بإرسال طلب لإنشاء مقال جديد في الموقع.
المتعارف عليه إذا تم إنشاء المقال بنجاح، هو أن يقوم السيرفر بإرجاع نسخة منه.
ملاحظة: قمنا إرسال بيانات المقال على شكل JSON للسيرفر.
المثال الثالث
// هنا قمنا بتعريف دالة تقوم بإرسال طلب إلى السيرفر بشكل متزامن و من ثم تعرض نتيجته async function fetchData() { // وضعنا فيه مسار الموقع الذي سنقوم بإرسال الطلب إليه url المتغير let url = 'https://jsonplaceholder.typicode.com/posts'; try { // url هنا قمنا بإرسال طلب إلى الرابط الموجود في // POST مع تحديد طريقة إرسال الطلب على أنها // JSON و أن البيانات المرسلة في الطلب موضوعة بأسلوب let response = await fetch(url, { method: 'POST', body: JSON.stringify({ title: 'This is the title', body: 'This is is the content', userId: 1 }), headers: { 'Content-type': 'application/json; charset=UTF-8' } }); // هنا قمنا بفحص الرد الذي أتى من السيرفر لمعرفة ما إن كان قد تم إنشاء المقال أم لا if (!response.ok) { // إذا حدثت أي مشكلة عند محاولة الإتصال بالموقع لإنشاء المقال، سيتم عرض النص التالي كخطأ throw new Error('Network response was not ok'); } // إذا تم إنشاء المقال بنجاح سيقوم السيرفر بإرجاع نسخة منه // و لكننا سنقوم بتحويلها إلى كائن جافاسكربت JSON على هيئة let data = await response.json(); // بعد أن تم تحويل رد السيرفر إلى كائن، سيتم عرض القيم الموجودة فيه document.write(` <p>The newely created post data:</p> <ul> <li>userId: ${data.userId}</li> <li>id: ${data.id}</li> <li>title: ${data.title}</li> <li>body: ${data.body}</li> </ul>`); } catch(error) { // إذا حصل أي خطأ أثناء جلب البيانات سيتم عرضه alert(error); } } // حتى تتنفذ fetchData() هنا قمنا باستدعاء الدالة fetchData();
في المثال التالي قمنا بحذف مقال واحد من الموقع و من بعدها قمنا بإظهار رسالة تفيد بأنه تم حذفه.
المثال الرابع
// هنا قمنا بتعريف دالة تقوم بإرسال طلب إلى السيرفر بشكل متزامن و من ثم تعرض نتيجته async function fetchData() { // وضعنا فيه مسار الموقع الذي سنقوم بإرسال الطلب إليه url المتغير let url = 'https://jsonplaceholder.typicode.com/posts/1'; try { // url هنا قمنا بإرسال طلب إلى الرابط الموجود في let response = await fetch(url, { method: 'DELETE' }); // هنا قمنا بفحص الرد الذي أتى من السيرفر لمعرفة ما إن كان قد تم الحذف بنجاح أم لا if (!response.ok) { // إذا كان رد السيرفر يفيد بأن الحذف قد فشل فسيتم // عرض النص التالي للإشارة إلى وقوع خطأ عند التنفيذ throw new Error('Network response was not ok'); } // إذا لم يقع أي خطأ فهذا يعني أنه تم الحذف بنجاح و سيتم إعلام المستخدم بذلك document.write(`The post is deleted successfuly.`); } catch(error) { // إذا حصل أي خطأ أثناء تنفيذ أو إرسال الطلب سيتم عرضه alert(error); } } // حتى تتنفذ fetchData() هنا قمنا باستدعاء الدالة fetchData();