اخیراً چند پروژهی وبسرویسی برام پیش اومد که خب با توجه به ترند بودن REST و البته کارا بودنش، از REST استفاده کردم؛ REST توسط آقای فیلدینگ مطرح شد و بعدها مدل تکامل اون، توسط آقای ریچاردسون ارائه شد؛ مدل تکامل REST، در واقع مسیر رسیدن به REST رو از هیچی ترسیم میکنه؛ یعنی ما فقط یه شبکه داریم و یه تعداد اپلیکیشن (سرور و کلاینت) که میخوان با هم اطلاعات رد و بدل کنن.
اگر بخوام خیلی مختصر بهش بپردازم، توی سطح صفر، صرفاً قرارداد میکنیم که از پروتکل HTTP برای صحبت کردن با هم استفاده کنیم؛ در سطح یک، قرارداد میکنیم که URLها به جای اینکه چیزی شبیه به اسم تابع باشن، مثل:
/updateDepartment ☒
به ریسورسها اختصاص پیدا کنن:
/departments ☑
در سطح دوم، از متدهای HTTP (مثل GET, POST, PUT و DELETE) برای انجام عملیاتهای مختلف روی ریسورسها استفاده میکنیم؛ مثلاً اگر کلاینت بخواد اطلاعات ادارهای با آیدی ۵ رو آپدیت کنه یک ریکوئست HTTP با متد PUT به همراه اطلاعات جدید، به آدرس:
/departments/5
میفرسته.
برای توضیحات بیشتر در مورد REST میتونید به مقالهی خوب دوست خوبم مهدی، اصول طراحی RESTful API / بهترین راهکارها، یه سر بزنید!
چیزی که اطلاعات دقیقی ازش نداشتم و همیشه ناراحت بودم که REST واقعی رو نتونستم پیاده کنم، کلمه بدطور HATEOAS، همون سطح سهی مدل تکامل بود.
تلفظ HATEOAS ظاهراً متفاوته؛ بعضیا میخونن heyties بعضیا heyt oas.
وقتی شما وارد یک سایت میشید، فقط آدرس اصلی اون سایت رو میدونید (مثلا virgool.io)؛ بعد با لینکهایی که داخل هر صفحه وجود داره، وارد قسمتهای مختلف سایت میشید و از امکاناتش استفاده میکنید؛ HATEOAS هم، همین امکان رو به کلاینت میده که فقط با داشتن یک آدرس شروع، بتونه به قسمتهای مختلف API دسترسی پیدا کنه و ازشون استفاده کنه.
برای مثال، وقتی کلاینت برای دریافت اطلاعات ادارهی ۵ به آدرس:
/departments/5
ریکوئست میفرسته این جواب رو میگیره:
توی این جواب علاوه بر دریافت اطلاعات اداره، لینک کارکنان اون اداره، مدیرش و آدرسش رو هم میگیره؛ عملاً با داشتن یک لینک، به تمام قسمتایی که باهاشون کار داشته دسترسی پیدا میکنه.
این ویژگی امکانات خوبی رو بوجود میاره؛ باعث میشه سرور و کلاینت مستقل از هم توسعه پیدا کنن؛ سرور خیلی راحت میتونه آدرس ریسورسها رو تغییر بده چون کلاینت پیش خودش آدرسی نگه نمیداره. نکتهی مثبت دیگه اینکه کلاینت میتونه توی APIها گشت و گذار کنه و بخشهای مختلف رو پیدا کنه؛ یعنی نیاز به مستندسازی کاهش پیدا میکنه. همچنین سرور میتونه قسمتهای جدید رو که به تازگی اضافه کرده در قسمت لینکها در پاسخ بیاره.
در مقابل، پیاده کردن HATEOAS سخته! چه از لحاظ فنی و چه از لحاظ معماری! خصوصاً اینکه ابهامات زیادی وجود داره؛ هیچ قرارداد مشترکی روی اینکه این لینکها از چه طریقی به دست کلاینت برسه وجود نداره؛ هم میتونید لینکها رو به شکلی که گفته شد، توی بدنه پاسخ بیارید، هم توی header اون. ابهام دیگهای که بهش برخورد کردم این بود که بعضی جاها لینکها، مشابه بالا، فقط href و rel داشتن، بعضی جاها علاوه بر اونها، type (که مشخص کننده متد http بود) رو هم آورده بودن.
از ابهامات صرف نظر کنیم، ابراز مناسب برای پیادهسازیش هم محدوده؛ البته که پروژههایی مثل Spring HATEOAS وجود دارن اما باز هم وقتی به نمونهکدها نگاه کنید پیادهسازی اون کار سادهای نیست. از همه بدتر، کلاینتهایی که از HATEOAS استفاده کنن هم، خیلی وجود ندارن (توی تجربهی محدود شخصیم که اصلاً وجود نداشت)؛ یعنی در نهایت مجبوریم، هم مستندات کاملی طراحی کنیم، هم یه فکری برای تکامل API، مثل ورژن دادن (v1/) بکنیم که البته آقای فیلدینگ از این موضوع خیلی شاکی هستن:
«دلیل ساخت REST API واقعی، بدست آوردن ویژگی تکامله؛ یک "v1"، یک فحش بد به کاربران API شماست که بجای REST همون RPC/HTTP ساختم!» نقل به مضمون از توییت فیلدینگ
با تمام این اوصاف، به نظر نمیاد صرف این حجم از زمان و انرژی برای پیاده کردن HATEOAS که در آخر احتمالاً با استقبال خیلی کمی از کلاینتها روبرو میشه معقول باشه؛ جایی میخوندم که به ساختن APIهای REST خودتون بدون HATEOAS ادامه بدید و اصرار داشته باشید که API خودتون رو REST صدا بزنید!
نظر شما چیه؟ خصوصا اینکه دیگه REST تنها راهکار برای ارائه وبسرویس نیست؛ راهکارهای جالب دیگهای مثل graphQL و gRPC هم هستن!
برای نوشتن این پست، مطالبی از اینجا و اینجا و اینجا و اینجا استخراج شد.