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 APIES6 ClassPromiseArrow Function
هدف این است که همان چهار عملیات اصلی HTTP را داشته باشیم:
GETPOSTPUTDELETE
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 استفاده میشود.
ایده کار این است که:
- آدرس را به
fetchبدهیم - پاسخ را بگیریم
- پاسخ را به JSON تبدیل کنیم
- داده نهایی را برگردانیم
اما چون 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 را ساختیم:
getpostputdelete
در نهایت، یک کتابخانه تمیزتر، قابلفهمتر و مدرنتر ساختیم که برای کار با APIها پایهای مناسب است.
در بخش بعد، همین کتابخانه را با async/await بازنویسی میکنیم تا کدها حتی سادهتر شوند.