[در این مقاله و مقالات مرتبط بعدی قصد داریم که مفهوم، شیوهی طراحی و پیادهسازی یک وبسرویس REST را آموزش دهیم. بخشی از این مطالب ترجمهای از مقالهای است که لینک آن در انتهای مقاله آمدهاست، لذا جایی که لفظ «من» در متن موجود باشد، اشاره به نویسندهی اصلی مقاله دارد. این مقاله در سطح «متوسط» و نیازمند آشنایی خوانند به مفاهیم «وبسرویس» و «پروتکل HTTP» است.]
واژهی REST مخفف شدهی Representational State Transfer (انتقال بازنمودی حالت) است. اگر شما در یاهو یا گوگل در مورد REST Web Services جستجویی انجام دهید، آنها خرواری از اطلاعات به شما میدهند. اما اگر شما هم مثل یک هفتهی پیش من باشید، این همه اطلاعات را بیشتر آزاردهنده میبینید تا مفید، چون میخواهید در کمترین زمان یک وبسرویس REST پیادهسازی کنید. ما، خواه آگاهانه خواه ناآگاهانه، همگی به دستورالعملهای آشپزگونه از اینترنت عادت کردهایم و برای انجام کاری به چیزی بیش از یک راهنمای گام به گام علاقه نداریم.
من، بهزودی، فهمیدم که پیادهسازی یک وبسرویس REST راه میانبری ندارد، و شما بایستی مفهوم REST را به طور کامل درک کرده باشید. من یک مثال مشابه سراغ دارم: فرد تازهکاری را در نظر بگیرید که برای یادگیری جاوا یا داتنت بهدنبال مقالهی سادهای با عنوان «چگونه طراحی شیءگرا انجام دهیم» باشد. درواقع، REST درست چیز مشابهی است! متخصصان این زمینه آن را یک شیوهی معماری میدانند، ولی من این مقاله را با حرفهای خودم مینویسم و از چیزهایی که خود مرا در وهلهی اول گیج کرده بود، پرهیز میکنم. به نظر من، REST جایی است که معماری و طراحی با یکدیگر ترکیب میشوند و تمام خطوط نازک میان این دو محو میگردد.
برای اینکه سریعاً به اصل مطلب برسیم، من با چیزهایی که یک برنامهنویس سنتی وبسرویس، که اطلاعی در مورد REST ندارد، باید بداند، شروع میکنم.
عبور از وبسرویسهای سنتی به طراحی REST
در مورد اینکه یک «وبسرویس سنتی» چیست، کمی فکر کنید. این یک واسط با متدهایی ارائه شده است. مشتریها زمانی که این واسط را نگاه میکنند، «اشیاء» را میبینند. یک «شیء» هیچگونه ورودی یا خروجی ندارد، زیرا هیچ کاری انجام نمیدهد. برای مثال، یک وبسرویس سنتی را در نظر بگیرید که اگر شهر را به آن بدهید، شرایط کنون آب و هوایی را به شما میدهد. این سرویس احتمالاً یک متد با نام GetWeatherInfo
دارد که یک نام شهر را بهعنوان ورودی دریافت میکند و شرایط آب و هوایی را بهعنوان خروجی به دست میدهد. درک اینکه یک مشتری چگونه از این متد استفاده میکند، ساده است.
اکنون، به جای مثال بالا، وبسرویسی را فرض کنید که شهرها را بهعنوان اشیاء مهیا میکند. بنابراین، اگر شما بهعنوان یک مشتری به آن نگاه کنید، بهجای متدی مانند GetWeatherInfo
، نام شهرهایی مانند لندن، نیویورک را میبینید. این شهرها هیچ متد کاربردیای با خود به همراه ندارند، و مانند گازهای خنثی هیچ واکنشی نشان نمیدهند.
اکنون ممکن است با خود فکر کنید «حالا من چطور میتوانم از آب و هوای یک شهر، مثلاً دالاس، مطلع شوم؟» اگر تنها چیزی که شما از وبسرویس میگیرید یک مجموعه از اشیاء باشد، مشخصاً شما نیاز به راهی دارید که برروی آن اشیاء کنشی انجام دهید. این اشیاء، در ذات خود، هیچ متدی ندارند، بنابراین، شما نیاز به «کنشهایی» د ارید که بتوانید آنها را برروی اشیاء اعمال کنید. اما هر «کنشی» برای هر «شیئی» قابل استفاده نیست، مثلا یک «سیب» را میتوان «خورد»، ولی یک «خودرو» را «سوار میشوند» و نمیخورند!
بنابراین، ما نیاز به مجموعهای از «کنشهای استاندارد» داریم که برای تمام اشیاء قابل استفاده باشد. احتمالاً اولین کنشی که به ذهن میرسد GET
است. کنش GET
یک کنش معکوس دارد با عنوان PUT
، که اطلاعاتی را در مورد شیئی بروز میکند. آیا این مفاهیم شباهتی به HTTP ندارد؟ زمانی که شما یک آدرس را در مرورگر اینترنت خود وارد میکنید، کاری که مرورگرتان انجام میدهد، شباهت بسیاری به آنچه من شرح دادم، دارد. اگر آدرسی که شما به مرورگر دادهاید را یک شیء فرض کنید، مرورگر برای به دست آوردن آن یک درخواست GET
ارسال میکند.
در واقع، HTTP پروتکلی است که به مشتری (در اینجا، مرورگر) این امکان را میدهد که یک درخواست GET
، PUT
، POST
، یا DELETE
را به سرور بفرستد. اگر به این کنشها درست فکر کنید، درمییابید که HTTP چقدر قدرتمند است و جستجوی شما برای یافتن کنشهای عمومی پایان مییابد. پاسخ در کنشهای HTTP نهفته است، و مجازاً با همین کنشهای محدود میتوان هر کاری انجام داد.
در اینجا عبور شما از وبسرویسهای سنتی به REST کامل میشود. یک وبسرویس REST تنها اشیاء را ارائه میدهد، و در کنار آن، کنشهایی را برای آن اشیاء مهیا میکند. در مثال پیشین ما، یک درخواست GET
به سرور اطلاعات آب و هوا، شهرها را برمیگرداند. اکنون اگر درخواستی مانند GET DALLAS
به سرور فرستاده شود، اطلاعات آب و هوای شهر دالاس به دست میآید. پاسخ این درخواست میتواند شامل هر اطلاعات دیگری دربارهی شهر دالاس باشد؛ مانند جمعیت یا تاریخچهی آن. البته، وبسرویس شما قرار نیست همهی این اطلاعات را ارائه کند.
پس، یک نام دامنهی مناسب، مانند weatherinfo، برای وبسرویس خود انتخاب کنید. بنابراین، مشتری درخواستی را مانند نمونهی زیر ارسال میکند:
GET http://weatherinfo.com/45327 HTTP/1.1
که در آن ۴۵۳۲۷ شناسهی شهر دالاس است. وبسرویس شما پاسخی شبیه نمونهی زیر به او بازمیگرداند:
HTTP/1.1 200 Ok Date: Sat, 03 Nov 2007 07:35:58 GMT Content-Type: text/xml Content-length: 138 <City name="Dallas" datetime="2007-11-03 07:35:58 GMT" > <Condition>Overcast</Condition> <Temp>69.5</Temp> <Humidity>80</Humidity> </City>
REST فقط دربارهی وبسرویسها نیست!
طراحان HTTP هدف مشابهی را در ذهن داشتهاند: ایجاد یک پروتکل ساده و همگانی برای ارتباط مشتری و سرویسدهنده. بنابراین، ما چرخی را دوباره اختراع نکردهایم؛ نوشتن یک وبسرویس REST چیزی فراتر از نوشتن یک برنامهی کاربردی وب نیست. اما، نه از لحاظ تکنولوژی، بلکه از لحاظ شیوهی استفاده، تفاوتهای مهمی نیز وجود دارد. بگذارید زمانی را به این تفاوتها اختصاص دهیم.
نخست، زمانی که یک مرورگر (یا مشتری) درخواست HTTP زیر را میدهد:
GET http://www.yahoo.com HTTP/1.0
انتظار بازگشتن دادههای بسیاری را میکشد: متن، سرخطها، عکسها، پیوندها و هر آنچه شما در صفحهی خانگی Yahoo مشاهده میکنید. همهی این اطلاعات با قالب HTML به مرورگر شما بازمیگردد. از سوی دیگر، وقتی مشتری از وبسرویس درخواستی برای به دست آوردن برخی اطلاعات میکند، این اطلاعات، معمولاً، در قالب ویژهای هستند. بنابراین، نخستین تفاوت بین یک برنامهی وب و یک وبسرویس، این است که پاسخ بهشدت در قالب و محتوا متغیر است.
در مرتبهی دوم، یک مرورگر بهندرت نیازمند دستوری جز GET
است، بنابراین، بسیاری از برنامههای کاربردی وب گونهای نوشته نشدهاند تا به دستورات PUT
یا DELETE
پاسخ دهند. البته، دستور POST
توسط بسیاری از سرورها پردازش میشود و این به این دلیل است که از POST
در میان دستورات HTTP بسیار سوء استفاده شده است. تقریباً در تمام موارد، یک برنامهی کاربردی وب از مشتریان میخواهد، تنها بهدلیل آنکه POST
انعطاف بیشتری دارد، از آن استفاده کنند.
در حالی که یک وبسرویس خوشساخت REST باید عملیاتهای GET
، POST
، PUT
، DELETE
و HEAD
را پیادهسازی کند. ما دربارهی جزئیات این عملیاتها در بخش دوم این سری مقالات صحبت خواهیم کرد.
دو چالش بزرگ برای مانند وب فکر کردن
شما ممکن است بپرسید: جایگزینی فراخوانی متدها در وب سنتی با عملیاتهای سادهی HTTP برای به دست آوردن همه چیز، چندان کار سادهای نیست. شما درست میگویید؛ ساده نیست. اما، ارزش تلاش کردن را دارد. بگذارید دو چالش بزرگ را بررسی کنیم:
- جایگزینی مناسب همهی عملیاتها با چند عملیات سادهی محدود جرأت میخواهد.
- مکانیزم درخواست/پاسخ وب به معنی آن است که باید بدون حالت بودن را بپذیرید.
به هرکدام از اینها تک تک میپردازیم. ما دریافتیم که چگونه میتوانیم متد GetWeatherInfo
را با عملیات GET
جایگزین کنیم. اما، چگونه میتوان متد پیچیدهای مانند GetLoanApprovalDecision
، یا در تجارت الکترونیک، چگونه میتوان متد Buy
را جایگزین نمود؟
طراحی یک وبسرویس REST، چنانچه خواهید آموخت، اساساً شامل دو گام است: تبیین اشیائی که ارائه میدهید، و سپس، تصمیم بر آنکه چطور عملیاتهای GET
، PUT
، POST
و DELETE
بر هرکدام از این اشیاء عمل خواهند کرد! این عملیاتها سلاحهای شما هستند. آیا محدودیتی دارند؟ از یک سو، بله! زیرا شما نمیتوانید متدی مانند GetLoanApprovalDecision
پیاده کنید. اما، محدودیت خوب است! محدویت، با اعمال قوانینی ساده و قدرتمند که به هیچ عنوان نامساسب نیستند، ما را مجبور میکند که وبسرویس را به روشی استاندارد طراحی کنیم. به طور مثال، آیا میتوان یک برنامهی طولانی و پیچیدهی نوشته شده به سی را به یک طراحی شیءگرا بدل کرد و همچنان بتوان همان کارها را انجام داد؟ البته که میشود! اگر شما نمیتوانید، باید بیشتر در این زمینه مطالعه کنید. به نظر من، طراحی REST درست چیز مشابهی است. اگر شما نمیتوانید GetLoanApprovalDecision
را در REST مدلسازی کنید، باید در مورد REST بیشتر مطالعه کنید. REST توانایی آن را دارد، اما شما نمیدانید چگونه!
اکنون به چالش دوم میپردازیم: بدون حالت بودن. اساس بدون حالت بودن بر آن استوار است که فراخوانی هر عملیات نباید نیاز به مراجعه به فراخوانی عملیاتهای پیشین داشته باشد. هر فراخوانی مستقل است. سرور نیاز ندارد که بداند در فراخوانیهای گذشته چه اتفاقی افتاده است. برای مثال، در مورد وبسرویسی که مشتری نیازمند فراخوانی Login
در بدو امر است، آیا این عملیات بدون حالت است؟ خیر! زیرا در پردازشهای بعدی، وبسرویس باید نتیجهی عملیات Login
را به خاطر بسپارد. REST چنین اجازهای نمیدهد، زیرا یک وبسرویس انعطافپذیر و گسترشپذیر حقیقی باید بدون حالت باشد. حالتها مسائل را آن قدر پیچیده میکنند که ارزشش را ندارد. مثلاً حضور حالتها بینابین فراخوانیها اجازهی پردازش درخواستهای متوالی را برروی ماشینهای مختلف نمیدهد.
در بخش دوم این سری، من به معرفی ویژگیهای طراحی وبسرویسهای REST، و همچنین، پیادهسازی آنها خواهم پرداخت. ما خواهیم دید که چطور یک سرویس و مشتری REST بسازیم.
ممنون. منتظر قسمت بعدی هستم.