MATIN MOLKARA
SERIES: JavaScript — PART 57 OF 108

57- آموزش جاوااسکریپت | ساخت کتابخانه EasyHTTP V2: ارتقا به استانداردهای مدرن ES6

در این بخش، نسخه دوم کتابخانه EasyHTTP را با بهره‌گیری از کلاس‌های ES6، Promises و Fetch API بازنویسی می‌کنیم. هدف اصلی، جایگزینی متدهای قدیمی AJAX و Callbackها با ساختاری مدرن، بهینه‌تر و خواناتر برای انجام عملیات‌های CRUD است.

آموزش گام‌به‌گام ساخت EasyHTTP نسخه 2 با Fetch API، Promise و ES6 Class

در این بخش، نسخه دوم کتابخانه EasyHTTP را می‌سازیم.
نسخه اول این کتابخانه با XMLHttpRequest، callback و prototypeهای ES5 نوشته شده بود.
در این نسخه، همان عملکرد را با ابزارهای مدرن‌تر بازنویسی می‌کنیم:

  • Fetch API
  • ES6 Class
  • Promise
  • Arrow Function

هدف این است که همان چهار عملیات اصلی HTTP را داشته باشیم:

  • GET
  • POST
  • PUT
  • DELETE

1) آماده‌سازی فایل‌ها

ابتدا یک فایل HTML ساده داریم که فقط فایل جاوااسکریپت را وارد می‌کند.
در این مرحله، چیزی داخل body لازم نیست، چون خروجی را در console بررسی می‌کنیم.

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>EasyHTTP V2</title>
</head>
<body>
  <script src="easyhttp2.js"></script>
  <script src="app.js"></script>
</body>
</html>

2) ساخت کلاس EasyHTTP

در نسخه جدید، به‌جای prototype از class استفاده می‌کنیم.
چون دیگر با XMLHttpRequest و this.xhr کار نمی‌کنیم، نیازی به constructor هم نداریم.

easyhttp2.js

class EasyHTTP {
  // متدها اینجا قرار می‌گیرند
}

در بالای فایل هم می‌توانیم یک کامنت معرفی اضافه کنیم:

/*
  EasyHTTP Library
  Version 2
*/

3) ساخت متد GET

اولین متدی که می‌سازیم، GET است.
این متد برای دریافت داده از API استفاده می‌شود.

ایده کار این است که:

  1. آدرس را به fetch بدهیم
  2. پاسخ را بگیریم
  3. پاسخ را به JSON تبدیل کنیم
  4. داده نهایی را برگردانیم

اما چون fetch و json() هر دو Promise برمی‌گردانند، باید خروجی را داخل یک Promise دیگر wrap کنیم تا استفاده از کتابخانه ساده و یکدست بماند.

کد get

class EasyHTTP {
  get(url) {
    return new Promise((resolve, reject) => {
      fetch(url)
        .then((res) => res.json())
        .then((data) => resolve(data))
        .catch((err) => reject(err));
    });
  }
}

توضیح قدم‌به‌قدم

  • fetch(url) درخواست را ارسال می‌کند.
  • res.json() داده پاسخ را به فرمت جاوااسکریپتی تبدیل می‌کند.
  • اگر همه چیز درست باشد، resolve(data) اجرا می‌شود.
  • اگر خطایی رخ دهد، reject(err) اجرا می‌شود.

4) استفاده از متد GET در فایل app.js

حالا در فایل app.js یک نمونه از کلاس می‌سازیم و درخواست GET می‌زنیم.

const http = new EasyHTTP();

http.get('https://jsonplaceholder.typicode.com/users')
  .then((data) => console.log(data))
  .catch((err) => console.log(err));

این کد چه می‌کند؟

  • یک instance از کلاس EasyHTTP می‌سازد
  • آدرس users از jsonplaceholder را درخواست می‌کند
  • خروجی را در console چاپ می‌کند
  • اگر خطایی رخ دهد، آن را نشان می‌دهد

5) چرا http.get() مستقیم داده برنمی‌گرداند؟

اگر این‌طور بنویسیم:

const users = http.get('https://jsonplaceholder.typicode.com/users');
console.log(users);

خروجی چیزی شبیه Promise خواهد بود، نه خود داده.
چون درخواست شبکه غیرهمزمان است و نتیجه فوراً آماده نمی‌شود.

به همین دلیل باید از .then() استفاده کنیم تا بعد از آماده شدن داده، آن را دریافت کنیم.


6) ساخت متد POST

حالا متد ارسال داده را اضافه می‌کنیم.
در POST باید:

  • method را روی POST بگذاریم
  • headers را تنظیم کنیم
  • داده را به JSON تبدیل کنیم
  • پاسخ را برگردانیم

کد post

class EasyHTTP {
  get(url) {
    return new Promise((resolve, reject) => {
      fetch(url)
        .then((res) => res.json())
        .then((data) => resolve(data))
        .catch((err) => reject(err));
    });
  }

  post(url, data) {
    return new Promise((resolve, reject) => {
      fetch(url, {
        method: 'POST',
        headers: {
          'Content-type': 'application/json'
        },
        body: JSON.stringify(data)
      })
        .then((res) => res.json())
        .then((data) => resolve(data))
        .catch((err) => reject(err));
    });
  }
}

توضیح

  • Content-type: application/json به سرور می‌گوید که بدنه درخواست JSON است.
  • JSON.stringify(data) آبجکت جاوااسکریپتی را به رشته JSON تبدیل می‌کند.
  • بعد از ارسال، پاسخ با res.json() خوانده می‌شود.

7) تست متد POST

در app.js یک آبجکت داده می‌سازیم:

const http = new EasyHTTP();

const data = {
  name: 'John Doe',
  username: 'John Doe',
  email: 'johndoe@gmail.com'
};

http.post('https://jsonplaceholder.typicode.com/users', data)
  .then((data) => console.log(data))
  .catch((err) => console.log(err));

خروجی

در پاسخ، یک آبجکت جدید می‌گیریم که شامل همان داده‌ها به‌همراه id جدید است.
مثلاً:

{
  name: "John Doe",
  username: "John Doe",
  email: "johndoe@gmail.com",
  id: 11
}

8) ساخت متد PUT

متد PUT برای به‌روزرسانی یک منبع موجود استفاده می‌شود.
ساختارش تقریباً مانند POST است، فقط نوع متد HTTP فرق می‌کند.

کد put

class EasyHTTP {
  get(url) {
    return new Promise((resolve, reject) => {
      fetch(url)
        .then((res) => res.json())
        .then((data) => resolve(data))
        .catch((err) => reject(err));
    });
  }

  post(url, data) {
    return new Promise((resolve, reject) => {
      fetch(url, {
        method: 'POST',
        headers: {
          'Content-type': 'application/json'
        },
        body: JSON.stringify(data)
      })
        .then((res) => res.json())
        .then((data) => resolve(data))
        .catch((err) => reject(err));
    });
  }

  put(url, data) {
    return new Promise((resolve, reject) => {
      fetch(url, {
        method: 'PUT',
        headers: {
          'Content-type': 'application/json'
        },
        body: JSON.stringify(data)
      })
        .then((res) => res.json())
        .then((data) => resolve(data))
        .catch((err) => reject(err));
    });
  }
}

9) تست متد PUT

برای تست، یک آبجکت جدید می‌سازیم و کاربری با شناسه مشخص را به‌روزرسانی می‌کنیم:

const http = new EasyHTTP();

const updatedData = {
  name: 'Jane Doe',
  username: 'Jane Doe',
  email: 'janedoe@gmail.com'
};

http.put('https://jsonplaceholder.typicode.com/users/2', updatedData)
  .then((data) => console.log(data))
  .catch((err) => console.log(err));

خروجی

کاربر با id برابر 2 به‌روزرسانی می‌شود و داده جدید در کنسول دیده می‌شود.


10) ساخت متد DELETE

برای حذف یک منبع، نیازی به ارسال body نداریم.
فقط کافی است نوع درخواست را DELETE قرار دهیم.

کد delete

class EasyHTTP {
  get(url) {
    return new Promise((resolve, reject) => {
      fetch(url)
        .then((res) => res.json())
        .then((data) => resolve(data))
        .catch((err) => reject(err));
    });
  }

  post(url, data) {
    return new Promise((resolve, reject) => {
      fetch(url, {
        method: 'POST',
        headers: {
          'Content-type': 'application/json'
        },
        body: JSON.stringify(data)
      })
        .then((res) => res.json())
        .then((data) => resolve(data))
        .catch((err) => reject(err));
    });
  }

  put(url, data) {
    return new Promise((resolve, reject) => {
      fetch(url, {
        method: 'PUT',
        headers: {
          'Content-type': 'application/json'
        },
        body: JSON.stringify(data)
      })
        .then((res) => res.json())
        .then((data) => resolve(data))
        .catch((err) => reject(err));
    });
  }

  delete(url) {
    return new Promise((resolve, reject) => {
      fetch(url, {
        method: 'DELETE',
        headers: {
          'Content-type': 'application/json'
        }
      })
        .then((res) => res.json())
        .then(() => resolve('Resource deleted'))
        .catch((err) => reject(err));
    });
  }
}

توضیح

در بسیاری از APIها، پاسخ DELETE ممکن است داده مفیدی نداشته باشد.
به همین دلیل، بعد از موفقیت‌آمیز بودن درخواست، یک پیام ثابت برمی‌گردانیم:

'Resource deleted'

11) تست متد DELETE

const http = new EasyHTTP();

http.delete('https://jsonplaceholder.typicode.com/users/2')
  .then((data) => console.log(data))
  .catch((err) => console.log(err));

خروجی

اگر درخواست موفق باشد، عبارت زیر چاپ می‌شود:

Resource deleted

12) نسخه کامل کتابخانه EasyHTTP V2

class EasyHTTP {
  get(url) {
    return new Promise((resolve, reject) => {
      fetch(url)
        .then((res) => res.json())
        .then((data) => resolve(data))
        .catch((err) => reject(err));
    });
  }

  post(url, data) {
    return new Promise((resolve, reject) => {
      fetch(url, {
        method: 'POST',
        headers: {
          'Content-type': 'application/json'
        },
        body: JSON.stringify(data)
      })
        .then((res) => res.json())
        .then((data) => resolve(data))
        .catch((err) => reject(err));
    });
  }

  put(url, data) {
    return new Promise((resolve, reject) => {
      fetch(url, {
        method: 'PUT',
        headers: {
          'Content-type': 'application/json'
        },
        body: JSON.stringify(data)
      })
        .then((res) => res.json())
        .then((data) => resolve(data))
        .catch((err) => reject(err));
    });
  }

  delete(url) {
    return new Promise((resolve, reject) => {
      fetch(url, {
        method: 'DELETE',
        headers: {
          'Content-type': 'application/json'
        }
      })
        .then((res) => res.json())
        .then(() => resolve('Resource deleted'))
        .catch((err) => reject(err));
    });
  }
}

جمع‌بندی

در این بخش، کتابخانه EasyHTTP را از نسخه قبلی ارتقا دادیم و با ابزارهای مدرن‌تر بازنویسی کردیم:

  • به‌جای XMLHttpRequest از fetch استفاده کردیم
  • به‌جای prototype از class استفاده کردیم
  • درخواست‌ها را با Promise مدیریت کردیم
  • چهار متد اصلی HTTP را ساختیم:
    • get
    • post
    • put
    • delete

در نهایت، یک کتابخانه تمیزتر، قابل‌فهم‌تر و مدرن‌تر ساختیم که برای کار با APIها پایه‌ای مناسب است.
در بخش بعد، همین کتابخانه را با async/await بازنویسی می‌کنیم تا کدها حتی ساده‌تر شوند.

// 0 comments
#JavaScript#ES6#EasyHTTP#Fetch API#Promises#Web Development#آموزش جاوااسکریپت#CRUD

نظرات (0)

نظر خود را بنویسید