Programming Basics SQL HTML CSS JavaScript React Python C++ Java JavaFX Swing Problem Solving English English Conversations Computer Fundamentals Linux Learn Typing

جافاسكربت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();
جرب الكود