امروزه برنامه های سنتی وب در حال حرکت به سمت سرویسی شدن هستند، بدین صورت که کلاینت ها تنها از طریق وب سرویسها با سرور در تماس هستند.به بیانی دیگر ارتباط کلاینت ها با لایه Data Model از طریق وب سرویس ها صورت می پذیرد.در چنین برنامه هایی منطق برنامه کاملا در سمت کلاینت پیاده سازی می شود و سرور دیگر هیچ نقشی جز فراهم کردن داده برای کلاینت هایش را برعهده ندارد.نمونه رایجی از این گونه نگرش برنامه نویسی,برنامه های SPA که مخفف Single Page Application است,می باشد.در اینگونه برنامه ها تمامی منطق برنامه در سمت کلاینت و پیاده سازی می شود و تنها نیازی که برنامه به سرور دارد، فراهم ساختن داده ها می باشد. این نگرش این امکان را می دهد که شما به راحتی و بدون هزینه بالا یک برنامه SPA را به یک برنامه دیگر، مثلا یک برنامه موبایل تبدیل کنید. تنها کاری که انجام می شود این است که باید یک کلاینت برای تلفن همراه بنویسید که از طریق همان API ها با سرور ارتباط برقرار کند.

در نگاه اول پیاده سازی و استفاده از وب سرویس های RESTful بسیار مطلوب و خوش آیند به نظر می رسند. اما باید دقت داشته باشید که اگر در طراحی و پیاده سازی آنها دقت لازم را نکنید، هزینه های جانبی زیادی را در آینده ممکن است به برنامه شما وارد کند که اکثر آنها نیز مربوط به هزینه اعمال تغییرات می باشند.به همین دلیل در این مطلب سعی شده مطالبی گفته شود که به طراحی هرچه بهتر وب سرویس های RESTful کمک کند.

اولین و مهمترین نکته ای که باید پیش از شروع به طراحی یک وب سرویس RESTful باید به آن توجه داشته باشید این است که طراحی یک سرویس خوب تنها یک فن نیست، بلکه یک هنر است و نیاز به خلاقیت دارد. در زیر به اصولی کلیدی در طراحی وب سرویس های RESTful اشاره شده است:

وب سرویس شما باید به صورت درست و به جا از استاندارد های وب استفاده کند. مثلا انواع مختلفی از کد های پاسخ HTTPوجود دارند که همه بصورت کلی معنی موفقیت آمیز بودن عملیات را دارند اما هر کدام جایگاه خاصی دارد که در حین استفاده باید به آن دقت نمود.
دقت داشته باشید همانطور که یک برنامه نویس برنامه اش را برای کاربر نهایی می نویسد، شما نیز وب سرویس تان را بعنوان یک برنامه برای برنامه نویس ها می نویسید. بنابراین در اینجا نیز اصل user friendly بودن مصداق دارد و باید به آن توجه نمود.وب سرویس باید طوری نوشته شود که یک برنامه نویس بتواند براحتی با آن کار کند.
اگر وب سرویسی طراحی میکنید خیلی مهم است که توسط مرورگر ها و از طریق نوار آدرس آنها قابل پیمایش باشد.
وب سرویس شما باید تا حد ممکن ساده و به راحتی قابل درک باشد. طوری آن را طراحی کنید که اعمال تغییرات بر اساس نیاز کاربر در آینده قابل انجام باشد.
در طراحی وب سرویس به کارایی و انعطاف پذیر بودن آن توجه کنید.
همانطور که UX برای برنامه های کاربردی مطرح می شود، در مورد وب سرویس ها نیز طوری باید آنها را طراحی کنید که برنامه نویسی که با آنها کار می کند تجربه خوبی داشته باشد.
این ها اصول و مواردی هستند که در تمامی مراحل طراحی وب سرویس ها باید همواره مد نظر قرار گرفته شوند.

URL ها و action ها در REST

شاید به توان گفت یکی از کلیدی ترین اصول طراحی سرویس های مبتنی بر REST جداسازی و طراحی API در قالب منابع منطقی متفاوت است. در واقع تمام هدف RESTاین است که این منابع را بگونه ای در اختیار کلاینت ها قرار دهد تا از آنها استفاده کنند، تغییراتی در آنها دهند و یا آنها را حذف کنند. یکی از نکات مثبت سرویس های RESTاین است که دسترسی کلاینت ها به این منابع از طریق درخواست های HTTP انجام می گیرد. این درخواست ها با متد های مختلفی می توانند ارسال شوند که هر یک معنا و مفهومی خاص را دارد. این متد ها عبارتند از GET، POST ، PUT، DELETE و … که کاربرد هریک با دیگری متفاوت است.

گفتیم که اصل در سرویس های REST فراهم کردن منابع برای کلاینت هاست. کلاینت ها نیز از طریق درخواست های HTTP باید به آنها دسترسی داشته باشند.بنابر این در سرویس های URL,REST ها نقش مهمی را بازی می کنند. آنها هستند که مشخص کننده یک منبع می باشند. بنابراین انتخاب نام مناسب برای آنها از اهمیت بسیاری برخوردار است. پیشنهاد می شود برای نام گذاری منابع از اسامی استفاده کنید. استفاده از اسامی به دلیل ماهیت و نحوه استفاده از وب سرویس RESTful خوانایی URL را برای استفاده کنندگان از وب سرویس بیشتر می کند.

خیلی از برنامه نویس ها در هنگام طراحی منابع وب سرویس خود به دنبال نگاشت یک به یک بین مدل های برنامه خود و منابع وب سرویس خود هستند. مثلا اگر مدلی بنام User دارند سعی دارند که برای دستیابی به مدل User منبعی به همین نام (user) را فراهم کنند. این مسئله بسیار خوب و مطلوب است. اگر بتوان چنین نگاشتی را فراهم کرد خیلی خوب است اما توجه داشته باشید که برقراری این نگاشت یک به یک ضروری نیست و مهمتر از آن خوانایی و با معنا بودن نام منابع شماست.

پس از تعیین نام برای منابع و تعریف آنها شما نیاز به تعریف عملیات مختلف بر روی منابع را دارید. شما باید مشخص کنید بر روی یک منبع (مثلا user) چه عملیاتی قابل انجام است و این عملیات چگونه باید توسط کاربر درخواست شده و توسط سیستم به actionهای شما نگاشت داده شوند. توجه داشته باشید که بر اساس اصول REST شما تنها مجاز به پیاده سازی عملیات محدودی بر روی هر منبع خود هستید. این تعداد را تعداد متد های HTTP مشخص میکند(POST، GET، PUT، DELETE، PATCH و …(. بر اساس این متد ها شما قادر به پیاده سازی عملیات CRUD برای منابع خود هستید.

اما چگونه سیستم,عمل نگاشت بین درخواست HTTP و عملیات CRUD را انجام می دهد؟ در جواب باید گفت این کار بر اساس متد های درخواست صورت می گیرد.

در زیر نحوه استفاده از متد ها و معنای هرکدام آورده شده است:

متد GET به منظور بازیابی و خواندن منبع استفاده می شود.

GET /users – Retrieves a list of users
GET /users/21 – Retrieves a specific user

متد POST زمانی استفاده می شود که بخواهیم منبع جدیدی را ایجاد کنیم.

POST /users – Creates a new user

متدهای PUT و PATCH برای دستکاری در یک منبع مورد استفاده قرار می گیرند.

PUT /users/21 – Updates user #21
PATCH /users/21 – Partially updates user #21

متد DELETE نیز به منظور حذف یک منبع مورد استفاده قرار می گیرد.

DELETE /users/21 – Deletes user #21

توجه داشته باشید که ما با استفاده از متد های HTTP توانستیم عملیات مختلفی را بر روی یک آدرس ( users/ ) پیاده سازی کنیم. هیج نیازی به آوردن نام عملیات یا متد مورد نظر در آدرس URL نیست که این مسئله باعث تمیز ماندن و خواناتر شدن آدرس های منابع در سرویس های REST می گردد و این مسئله جزو نقاط قوت سرویس های REST نسبت به سایر سرویس ها می باشد.
حال این سوال را باید پاسخ دهیم که نام منابع بهتر است مفرد بیاید یا جمع؟ جواب این است که اگرچه در قواعد گرامری استفاده از اسم جمع برای یک منبع واحد صحیح نیست، اما در این جا باید گفت که به منظور بالا بردن خوانایی و با معنا تر شدن نام های منابع توصیه می شود که از نام های جمع استفاده کنید. بنابراین بجای استفاده از /user از /users استفاده کنید.

در یک برنامه کاربردی در بسیاری از مواقع ممکن است در کنار یک منبع بخواهیم به منابع مرتبط با آن نیز دستیابیم. بنابراین این سوال مطرح می شود که برای دستیابی به چنین ارتباطاتی آدرس های URL باید به چه صورتی طراحی شوند. البته در اینجا بایدی وجود ندارد اما پیشنهاد می شود برای دستیابی به منابع مرتبط با یک منبع مانند مثال های زیر عمل کنید. در این مثال ها قصد داریم در کنار دستیابی به منبع user پیام های مرتبط به آن را نیز بازیابی یا دستکاری نماییم :

اگر بخواهیم تمامی پیام های مرتبط با user شماره ۲۱ را بازیابی کنیم بهتر است URL بصورت زیر طراحی شود :

GET /users/21/messages – Retrieves list of messages for user #21

اگر بخواهیم یک پیام خاص از یک user خاص را بازیابی کنیم پیشنهاد می شود بصورت زیر عمل شود:

GET /users/21/messages/7 – Retrieves message #7 for user #21

برای ایجاد، ویرایش و حذف یک پیام در رابطه با یک user خاص فراخوانی سرویس بصورت زیر می باشد :

POST /users/21/messages – Creates a new message in user #21
PUT /users/21/messages/7 – Updates message #7 for user #21
PATCH /users/21/messages/7 – Partially updates message #7 for user #21
DELETE /users/21/messages/7 – Deletes message #7 for user #21

توجه داشته باشید چنانچه منبع مرتبط با منبع اصلی بطور متداول در برنامه شما مورد استفاده قرار می گیرد,برای جلوگیری از ارسال دو در خواست پشت سر هم به سرور (مانند آنچه در روش بالا آن مواجه خواهیم شد) بهتر است منبع وابسته در داخل رشته پاسخ به کلاینت افزوده شود. در این صورت هنگامی که لیست user ها را دریافت می کنیم در کنار هر user پیام های آنها نیز دریافت می شوند. و دیگر کلاینت نیاز به ارسال در خواست دوم برای گرفتن پیام ها نمیباشد.
در طراحی سرویس های REST توسعه دهنده در برخی مواقع نیاز به استفاده از خلاقیت دارد تا بتواند به بهترین شکل ممکن URLمربوط به منابع خود را تعریف کند. فرض کنید action ای در برنامه دارید که در قالب عملیات CRUD نمی توان آن را گنجاند. مثلا فرض کنید می خواهید امکانی را به کلاینت بدهید تا یک کاربر را فعال یا غیر فعال کند. البته این کار را می توان با همان متد UPDATE برای کاربران انجام داد. اما فرض کنید شما می خواهید متدی مخصوص این کار را برای کلاینت فراهم کنید. در چنین مواقعی کار کمی خلاقیتی می شود و راهکار جامعی برای آن وجود ندارد.

یک روش این است که شما action را طوری تغییر دهید که همانند یک فیلد از منبع بنظر برسد. مثلا اگر می خواهید منبع را فعال کنید، action فعال سازی می تواند بصورت یک فیلد فعالسازی مثلا activated از نوع Boolean طراحی شود که با متد PATCHفراخوانی می شود. البته این روش وقتی خوب عمل می کند که action پارامتر نگیرد.

روش دیگر این است که Action بصورت یک sub-resource از منبع طراحی شود. برای مثال در GitHub برای ستاره دار کردن یک gist از فراخوانی PUT /gists/:id/star استفاده می شود. همانطور که می بینید action مربوط به ستاره دار کردن (star) بصورت زیر منبعی ازgists استفاده شده است. برای حذف ستاره نیز از DELETE /gists/:id/start استفاده می شود.

حال شرایطی را در نظر بگیرید که می خواهید چندین منبع را جستجو کنید. در چنین حالتی هیچ راه منطقی برای نگاشت action به یک ساختار منطبق با REST وجود ندارد. در چنین حالتی می توانید یک منبع خاص مثلا /search را در اختیار کاربر قرار دهید. دقت کنید که لغت Search در اینجا نام نیست. بلکه یک فعل است. اما بدلیل آنکه برای این منبع خاص بسیار منطقی و قابل فهم می باشد ما در اینجا بجای استفاده از اسامی جمع، از یک فعل استفاده کردیم. بنابراین می بینید که در مواقع مختلف نیاز است بسته به شرایط تصمیمات خاص گرفته شود. استفاده از Search در اینجا این کمک را می کند که بدون نیاز به مستندات زیادی به برنامه نویس سمت کلاینت بدون آنکه دچار سردرگمی شود اطلاع دهیم که کار این منبع جستجو است.

نمایش قابل چاپ