در حال ارتباط با سرور...




لطفا نظرات و پيشنهادات خود را بمنظور ارتقاء کيفي هرچه بيشتر سايت با ما در ميان بگذاريد.

ویدیوها مقالات کتاب ها اخبار پرسش و پاسخ
برنامه‌های رومیزی مبتنی بر وب زبان های برنامه سازی پایگاه داده سیستم عامل شبکه 
مقاله بگذارید
توسط : hamedkh دسته بندی : مبتنی بر وب تاریخ : 1392-12-29 21:39:39

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

 

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

 

در نگاه اول پیاده سازی و استفاده از وب سرویس های REST بسیار مطلوب و خوش آیند به نظر می رسند. اما باید دقت داشته باشید که اگر در طراحی و پیاده سازی آنها دقت لازم را نکنید، هزینه های جانبی زیادی را در آینده ممکن است به برنامه شما وارد کند که اکثر آنها نیز مربوط به هزینه اعمال تغییرات می باشند. بهمین دلیل در این پست آموزشی که بر گرفته شده است بهترین روش های طراحی سرویس های REST می باشد قصد داریم نکاتی را بیان کنیم که به طراحی هرچه بهتر وب سرویس های REST کمک کند. در این مقاله آموزشی قصد اینست که به سوالات زیادی که در حین طراحی بک API مطرح می شود پاسخ دهیم. مثلا اینکه از چه فرمت داده ای برای انتقال اطلاعات بین کلاینت و سرور استفاده کنیم؟ احراز هویت را چگونه انجام دهیم؟ آیا نسخه بندی (Versioning) لازم است؟ و سوالاتی از این دست.

 

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

 

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

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

این ها اصول و مواردی هستند که در تمامی مراحل طراحی وب سرویس ها باید همواره مد نظر قرار گرفته شوند.

 

URL ها و action ها در REST:

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

 

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

 

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

 

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

 

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

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

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

 

GET /tickets - Retrieves a list of tickets

GET /tickets/12 - Retrieves a specific ticket

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

POST /tickets - Creates a new ticket

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

PUT /tickets/12 - Updates ticket #12

PATCH /tickets/12 - Partially updates ticket #12

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

DELETE /tickets/12 - Deletes ticket #12

 

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

 

حال این سوال را باید پاسخ دهیم که نام منابع بهتر است مفرد بیاید  یا جمع؟ جواب اینست که اگرچه در قواعد گرامری استفاده از اسم جمع برای یک منبع واحد صحیح نیست، اما در این جا باید گفت که بمنظور بالا بردن خوانایی و با معنا تر شدن نام های منابع توصیه می شود که از نام های جمع استفاده کنید. بنابراین بجای استفاده از /user از /users استفاده کنید.

 

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

  • اگر بخواهیم تمامی پیام های مرتبط با ticket شماره 12 را بازیابی کنیم بهتر است URL بصورت زیر طراحی شود :

GET /tickets/12/messages - Retrieves list of messages for ticket #12

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

GET /tickets/12/messages/5 - Retrieves message #5 for ticket #12

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

POST /tickets/12/messages - Creates a new message in ticket #12

PUT /tickets/12/messages/5 - Updates message #5 for ticket #12

PATCH /tickets/12/messages/5 - Partially updates message #5 for ticket #12

DELETE /tickets/12/messages/5 - Deletes message #5 for ticket #12

 

توجه داشته باشید چنانچه منبع مرتبط با منبع اصلی بطور متداول در برنامه شما مورد استفاده قرار می گیرد برای جلوگیری از ارسال دو در خواست پشت سر هم به سرور (مانند آنچه در روش بالا آن مواجه خواهیم شد) بهتر است منبع وابسته در داخل رشته پاسخ به کلاینت افزوده شود. در این صورت هنگامی که لیست ticket ها را دریافت می کنیم در کنار هر ticket پیام های آنها نیز دریافت می شوند. و دیگر کلاینت نیاز به ارسال در خواست دوم برای گرفتن پیام ها نمیباشد.

 

در طراحی سرویس های 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 در اینجا این کمک را می کند که بدون نیاز به مستندات زیادی به برنامه نویس سمت کلاینت بدون آنکه دچار سردرگمی شود اطلاع دهیم که  کار این منبع جستجو است.

استفاده از SSL

همیشه و بدون هیچ استثنائی از SSL استفاده کنید. توجه داشته باشید که API شما از هر نقطه ای که دسترسی به اینترنت داشته باشند قابل دسترسی است. بنابراین اگر داده های ارسالی و دریافتی شما رمزگذاری نشوند براحتی قابل شنود هستند و یک تهدید امنیتی برای سیستم شما بشمار می روند.

 

یکی دیگر از مزایای استفاده از SSL اینست که احراز هویت کلاینت ها تضمین می شود و دیگر نیاز به sign کردن API ها نیست. نکته مهم دیگر که باید مد نظر قرار دهید اینست که اگر کلاینتی خواست بدون SSL به URL های API شما دسترسی پیدا کند آن را به هیچ وجه به URL های SSL خود هدایت (redirect) نکنید. بجای این کار خطایی به او باز گردانید. بنابراین دسترسی را به URL های SSL محدود کنید.

 

مستند سازی:

یک API خوب باید مستندات خوبی نیز داشته باشد. این مستندات باید براحتی و برای همه برنامه نویسانی که قصد دارند از API شما استفاده کنند قابل دستیابی باشند. دقت داشته باشید که بیشتر برنامه  نویسان پیش از آنکه از API شما استفاده کنند مستندات شما را مطالعه می کنند. بنباراین اگر مستندات شما در قالب فایل های PDF باشند و یا اینکه برای دسترسی نیاز به لاگین داشته باشند هم دسترسی به آنها دشوار می شود و هم آنکه نمی توان با جستجو انها را براحتی یافت. بنابراین پیشنهاد می شود آنها را در قالب  هایی مانند HTML منتشر نمایید.

 

دقت داشته باشید که مستندات شما علاوه بر توضیحات بهتر است مثال های کاملی از نحوه ارسال درخواست و دریافت پاسخ داشته باشید. ترجیحا طوری این مثال ها را بنویسید که بتوان آن را براحتی copy/paste کرد. اگر لینک درخواست ها نیز قابل کپی شدن باشند به برنامه نویسانی که قصد استفاده از API شما را دارند بسیار کمک خواهد کرد.

 

نکته مهم دیگری که باید توجه کنید اینست که هر گونه بروز رسانی در API خود را باید در مستندات بیاورید. بعنوان مثال درخواست هایی که دیگر نباید استفاده شوند یا deprecate شده اند و آخرین تغییرات در نحوه دستیابی به API باید به برنامه نویسان اطلاع داده شود. بهتر است این کار را بصورت changelog و یا mailing list انجام دهید.

 

Versioning

همیشه و همیشه API خود را نسخه بندی کنید. این مسئله باعث می شود که تکامل API شما راحت تر صورت پذیرد و از به مشکل خوردن کلاینت ها در هنگام تغییرات جلوگیری نماید. شما می توانید تغییرات را براحتی در ورژن جدید اعمال کنید و اجازه دهید کلاینت های قدیمی تر با ورژن قدیمی بدون هیچ مشکلی به کار خود ادامه دهند.

 

اما سوال اینجاست که ورژن بهتر است در URL مشخص گردد و یا در header درخواست. نظرات مختلفی در این باره وجود دارد. اگر بخواهیم بطور آکادمیک بگوییم بهتر است ورژن در header مشخص شود. اما پیشنهاد می شود که ورژن در URL مشخص شود تا بتوان از پشتیبانی مرورگر نیز بهره مند شد. اگر بیاد داشته باشید در ابتدای این بحث گفتیم که یکی از ویژگی های API خوب ایسنت که بتوان از طریق نوار آدرس آن را پیمایش کرد.

 

روشی که در اینجا می خواهیم پیشنهاد کنیم آنست که ورژن های اصلی API را در URL مشخص کنید. اما تغییرات جزئی را بدون تغییر ورژن اصلی و با ایجاد زیر ورژن هایی در header در خواست تعیین کنید. بعنوان مثال در URL شما ورژن v1 را مشخص می کنید در header نیز می توانید زیر ورژن های ان را مانند 1.0.1 را تعیین نمایید که نشان دهنده تغییرات جزئی تر هستند.

 

هیچ API ای وجود ندارد که کاملا stable و بدون تغییر باقی بماند. بنابراین ورژن دهی به API یکی از مهمترین کارهایی است که همواره باید آن را مد نظر قرار دهید تا بتوانید مدیریت بهتری بر روی تغییرات خود داشته باشید. همواره مستندات خود را بروز نگه دارید و تغییرات API خود را به اطلاع برنامه نویسان کلاینت ها برسانید.

 

فیلتر کردن، مرتب کردن و جستجو در نتایج

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

 

فیلتر کردن :

هنگامی که می خواهید نتایج را فیلتر کنید به ازای هر فیلدی که می خواهید فیلتر کنید یک پارامتر در نظر بگیرید و آن را در URL قرار دهید. بعنوان مثال فرض کنید می خواهیم لیستی از کاربران فعال را از سرور دریافت کنیم. در این صورت بهتر است URL شما بصورت /users?state=active باشد. در این جا state پارامتری است که بر اساس آن می خواهیم نتایج را فیلتر کنیم.

 

مرتب سازی:

همانند آنچه در مورد فیلترینگ داشتیم، برای مرتب سازی نیز پارامتری را به URL اضافه می کنیم. معمولا این پارامتر با نام sort اضافه می شود. بعنوان مثال اگر بخواهیم کاربران را بر اساس تاریخ تولدشان مرتب کنیم پیشنهاد می شود بصورت زیر این کار انجام شود :

/users?sort=-birth_date

در مثال بالا با –birth_date مشخص می کنیم که می خواهیم نتایج را بصورت نزولی مرتب  سازی کنیم. اگر بخواهیم مرتب سازی را بر اساس پارامتر های دیگر نیز انجام دهیم پیشنهاد می شود لیست پارا متر ها را با کاما از هم جدا کرده و همه را با هم در قالب پارامتر sort ارسال کنیم. بعنوان مثال اگر بخواهیم کاربران را بر اساس نام و نام خانوادگی مرتب کنیم می توان بصورت زیر عمل نمود :

GET /users?sort=first_name,laste_name

 

جستجو کردن:

در هنگام جستجو کردن در صورتی که از جستجوی تمام متن (full text) استفاده می کنید پیشنهاد می شود با پارامتری بنام q را برای مشخص کردن رشته مورد جستجو در URL اضافه نمایید.

می توان با ترکیب این سه مورد URL های پیچیده ای و در عین حال خوانایی را بصورت زیر ایجاد نمود :

 

GET /tickets?sort=-updated_at

GET /tickets?state=closed&sort=-updated_at

GET /tickets?q=return&state=open&sort=-priority,created_at

 

استفاده از نام های مستعار (alias) برای برخی از پرس و جو های رایج

برخی از پرس و جو ها ممکن است بسیار رایج و مورد استفاده باشند. بد نیست برای راحتی کار استفاده کنندگان API های خود این پرس و جو ها را در قالب URL های خاصی در اختیار آنها قرار دهید. بعنوان مثال گرفتن آخرین لیست آخرین محصولات را می توانید در قالب یک مسیر مجزا مثلا GET /products/recently_added در اختیار کاربران قرار دهید.

 

موفق و پیروز باشید

hamedkh
5.8 k     1     15     63
نظرات

واقعا عالی بود

دم شما گرم مطلب خیلی خوبی بود از شما سپاسگذارم http://parsiprozhe.ir