SOAP بررسی پروتکل

SOAP چیست؟ مخفف Simple Object Access Protocol و یک پروتکل مبتنی بر XML برای رد و بدل کردن اطلاعات بین برنامه ها است. اطلاعات در SOAP به صورت پیام (Message) و از طریق پروتکل‏های موجود در اینترنت مانند HTTP منتقل می‏شود (SOAP در سایر پروتکل ها، مانند SMTP یا MIME نیز قابل استفاده است). به زبان ساده‏ تر، SOAP یک پروتکل برای دستیابی به یک سرویس ارایه شده در وب (Web Service) است. برخی از ویژگیهای SOAP‌ عبارتند از : • وابسته به محیط پیاده سازی و اجرا نیست. ( Platform Independent) • یک پروتکل ارتباطی مبتنی بر XML است. • از دیوارهای آتش (Firewall) گذر می‏کند ودیوارهای آتش مانع آنها نمی شوند (Block نمی‏شوند). • برای ارسال پیام استفاده می‏شود. • برای محیط اینترنت و شبکه طراحی شده اند.

⦁ SOAP stands for Simple Object Access Protocol ⦁ SOAP is an application communication protocol ⦁ SOAP is a format for sending and receiving messages ⦁ SOAP is platform independent ⦁ SOAP is based on XML

⦁ An Envelope element that identifies the XML document as a SOAP message ⦁ A Header element that contains header information ⦁ A Body element that contains call and response information ⦁ A Fault element containing errors and status information

وب سرویس Rest

امروزه برنامه های سنتی وب در حال حرکت به سمت سرویسی شدن هستند، بدین صورت که کلاینت ها تنها از طریق از طریق وب سرویس هایی با سرور در تماس هستند. به بیانی دیگر ارتباط کلاینت ها با لایه داده برنامه (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 در اختیار کاربران قرار دهید.  

مبتنی بر REST فکر کنید اگر این مقاله را میخوانید، احتمالا در مورد طراحی رابطهای برنامه نویسی حساس هستید و دوست دارید از اصول طراحی اثبات شده در طراحی Web API خود استفاده کنید. چون REST بیشتر استایل معماری نرم افزار می باشد تا استاندارد موکد، بنابراین انعطاف پذیری خوبی دارد. بدلیل همین آزادی ساختار و انعطاف پذیری، فرصت مناسبی برای طراحی بهترین راهبردها وجود دارد. این مقاله مجموعه ای از راهکارهای طراحی است که هنگام همکاری با چندین تیم طراحی API در شرکت Apigee توسعه داده ایم. ما نقطه نظر خود را در طراحی API - عملگرا - مینامیم زیرا این راهکار، موفقیت برنامه نویس را مهمتر از هر اصل دیگری قرار میدهد. برنامه نویس مشتری API می باشد. موفقیت  طراحی API با این سنجیده میشود که برنامه نویسان چقدر سریع میتوانند از ‌API شما استفاده موفقیت آمیز داشته باشند. ما طرفدار افراطی رست نیستیم ! طراحی API از منظر بیرون به درون بررسی خواهد شد. یعنی با این سوال شروع میکنیم: هدف ما از طراحی API چیست؟  وظیفه API این است که تاجایی که ممکن است برای برنامه نویس مفید باشد. طراح API باید از دید یک برنامه نویس استفاده کننده از سرویس به آن نگاه کند. اسم خوب است؛ فعل بد اصل اول طراحی عملگرا مبتنی بر رست (Restful) : همه چیز را ساده نگه دارید. آدرس پایه خود را ساده و واضح نگه دارید آدرس (URL) پایه مهمترین بخش در کارایی API شماست. یک آدرس پایه ساده و واضح استفاده از API شما را آسان میکند. کارایی بدین معناست که چیزی بدون استفاده از مستندات قابل استفاده باشد. برای مثال در مورد دستگیره یک در، بدون نیاز به مستندات شما میدانید که به کدام طرف باز و به کدام طرف بسته میشود. یک تست کلیدی در مورد طرح یک Web API این است که حتما باید فقط دو آدرس پایه برای هر منبع وجود داشته باشد. اجازه دهید یک API در مورد یک شی یا منبع ساده - یک سگ - را مدل سازی کنیم و یک API برای آن ایجاد نماییم. آدرس اول برای یک مجموعه است و دومی برای یک عنصر خاص در مجموعه. /dogs /dogs/1234 افعال را از آدرسهای پایه خود خارج کنید بسیاری از Web API ها از یک رهیافت مبتنی بر متد (method-driven) برای طراحی آدرسها استفاده میکنند. این آدرسهای مبتنی بر متد، گاهی در ابتدا و گاهی در انتها شامل افعال میشوند. برای هر منبع که شما مدل میکنید، مثل سگ مثال بالا، نمیتوانید همیشه یک آیتم تکی را در نظر بگیرید. همیشه منابع مرتبط و جذابی در مورد آن وجود دارند؛ مثل صاحب سگ، غذا، غلاده، نژاد و … در مورد فرخوانی متدهایی که برای دنیای کوچک یک سگ نیاز است فکر کنید. خیلی سریع شما لیست بلند بالایی از متدهایی خواهید داشت که از الگوی واحدی پیروی نمیکنند و برای توسعه دهندگان استفاده از API شما سخت خواهد بود. از افعال HTTP برای اعمال روی مجموعه ها و عناصر استفاده کنید برای منبع سگ، ما دو آدرس پایه که از اسمها و برچسبها استفاده میکنند داریم و میتوانیم روی آنها با افعال HTTP عمل کنیم. افعال HTTP عبارتند از : POST, GET, PUT و DELETE. میتوانیم این افعال را معادل اصطلاح CRUD در دنیای پایگاه داده بدانیم (CREATE-READ-UPDATE-DELETE). با دو منبع خود (/dogs و /dogs/1234) و چهار فعل HTTP، به مجموعه از قابلیتها میرسیم که برای برنامه نویسان آشناست. در زیر چارتی وجود دارد که نحوه استفاده از آنها را نشان میدهد. نکته در این است که احتمالا برنامه نویسان برای فهمیدن نحوه عملکرد API ما نیازی به این چارت نخواهند داشت. آنها میتوانند بدون استفاده از مستندات، API  را آزمایش کنند و آن را یاد بگیرند. بطور خلاصه: از دو آدرس پایه برای هر منبع استفاده کنید. از افعال در آدرسهای پایه خود استفاده نکیند. از افعال HTTP برای اعمال روی مجموعه ها و عناصر استفاده کنید. اسامی جمع و اسامی واقعی در ادامه نحوه انتخاب اسم برای منابع را شرح میدهیم. آیا باید از اسامی مفرد یا جمع برای منابع خود استفاده کنید؟  میدانید که API های محبوب از هردو استفاده میکنند. با هم به چند مثال نگاه میکنم : Foursquare: /cheins GroupOn: /deals Zappos: /Product با توجه به اینکه اولین کاری که ممکن است افراد با یک RESTful API انجام دهند اجرای یک GET است، بنابراین ما فکر میکنیم استفاده از اسامی جمع بهتر می باشد. اما مهمتر از آن این است که از یک مدل مخلوط که برخی آدرسهایتان مفرد و برخی جمع باشند استفاده نکنید. یکنواخت بود به برنامه نویسان اجازه میدهد که فراخوانی های متد را پیش بینی کنند و بتوانند براحتی با API شما کار کنند. اسامی واقعی از اسامی مجازی بهتر هستند رسیدن به مجردسازی محض هدف برخی از معماران API می باشد. هر چند این مجازی سازی همیشه برای برنامه نویسان قابل فهم نیست. بعنوان مثال یک API که به محتوا از طریق فرمهای مختلف مثل وبلاگ، ویدیو، اخبار و یا غیره دسترسی دارد. اگر این API همه چیز را با بیشترین درجه مجردسازی مدل کند - مثل /items یا /assets - فرصت این که برنامه نویسان بتوانند تصویر واضحی از نحوه کار API را داشته باشند از دست میدهد. این بسیار قابل فهمتر و مفید تر است که منابع تحت عناوینی مانند وبلاگها، ویدیوها  و اخبار لیست شوند. میزان مجردسازی به سناریوی شما بستگی دارد. شما باید تعداد قابل مدیریتی از منابع داشته باشید. هدف خود را استفاده از نامهای واقعی قرار دهید و سعی کنید تعداد منابع را بین 12 تا 24 حفظ کنید. در مجموع : یک API کاربردی از اسامی جمع به جای اسامی مفرد و از اسامی واقعی به جای مجرد استفاده میکند. وابستگی ها را کم کنید - پیچیدگی را پشت علامت ؟ پنهان کنید. در این بخش وابستگیهای بین منابع و پارمترهایی نظیر وضعیتها و صفات را در نظر خواهیم گرفت. وابستگی ها منابع همیشه به منابع دیگر وابستگی دارند. راه ساده برای نمایش این وابستگی ها در یک Web API چیست؟ اجازه دهید دوباره به API ای که در بالا مدل کردیم نگاه کنیم. ما از افعال HTTP برای اعمال روی منابع استفاده میکنیم. سگهای ما حتما صاحبانی دارند. برای اینکه تمام سگهایی که به یک فرد خاص تعلق دارند را لیست کنیم، یا یک سگ جدید برای آن شخص ایجاد کنیم از یک GET و POST استفاده خواهیم کرد : GET /owners/5678/dogs POST /owners/5678/dogs حالا، روابط میتوانند پیچیده تر شوند. صاحبان سگها میتوانند با دامپزشکان و آنها با سگها که آنها نیز با غذا ها ارتباط دارند، مرتبط هستند. این که از یک رشته بلند استفاده کنیم و آدرسی با عمق 5 یا 6 مرحله داشته باشیم معمول نیست. به یاد داشته باشید وقتی شما کلید اولیه را برای یک مرحله در اختیار دارید دیگر نیازی به مراحل بالاتر ندارید. به عبارت دیگر در بسیاری از موارد به عمقی بیشتر از /resource/identifier/resource نیاز ندارید. پیچیدگی را پشت علامت سوال پنهان کنید اکثر API ها پیچیدگیهایی در پس آدرس پایه یک منبع دارند. این پیچیدیگها میتواند شامل وضعیتهای مختلف که باید بروز، جستجو یا حذف شوند باشند. برای برنامه نویسان استفاده از آدرس پایه را با اضافه کردن وضعیتها و صفات اختیاری به انتهای علامت سوال HTTP ساده کنید. برای مثال لیست تمام سگهای قرمزی که در پارک در حال دویدن هستند : GET /dogs?color=red&state=running&location=park خلاصه : API خود را با ساده کردن روابط بین منابع و جاسازی پارمترها و پیچیدگی های دیگر در پشت علامت سوال HTTP ساده تر کنید. مدیریت خطاها بسیاری از برنامه نویسان از جمله خود من، دوست ندارند در مورد استثناها و خطاهایی که در برنامه رخ میدهد فکر کنند. اما مدیریت خطاها یک قطعه مهم از پازل نرم افزار و بخصوص یک API می باشد. چرا مدیریت خطا برای طراحان API مهم است؟ از نگاه برنامه نویسی که از API شما استفاده میکند، هر چیزی در پس API شما یک جعبه سیاه است. بنابراین خطاها یک ابزار کلیدی برای فراهم آوردن محتوا و وضوح در نحوه استفاده از API شما هستند. در ابتدا توسعه دهندگان یاد میگیرند از طریق خطاها یاد بگیرند. مفهوم - ابتدا تست - در متدولوژی extreme و اخیرا مدلهای توسعه مبتنی بر تست الگوهای جامعی در این مورد ارایه میدهند. در ضمن علاوه بر استفاده از خطاها در هنگام توسعه برنامه ها، برنامه نویسان به خروجی این خطاها در هنگام اشکالزدایی و حل مشکلات برنامه هایی که نوشته اند نیاز دارند. در مدل عملگرا چگونه در مورد خطاها فکر کنیم؟ اجازه دهید راهبرد سه API برتر را در این مورد مرور کنیم : Facebook: HTTP Status Code : 200 {“type”:”OauthExecption”,”message”:”(#803) Some of the aliases you requested do not exist: foo.bar”} Twilio: HTTP Status Code : 401 {“status”:”401”,”message”:”Authenticate”,”code”:20003,”more info”:”http://www.twilio.com/docs/errors/20003”} SimpleGeo HTTP Status Code : 200 {“code”:401,”message”:”Authentication Required”} Facebook مهم نیست که از در یک درخواست از Facebook چه اتفاقی بیفتد، شما همیشه یک کد وضعیت 200 به این معنا که همه چیز درست است دریافت میکنید. اکثر پیغامهای خطا هم در داخل پاسخ HTTP جاسازی میشوند. در مثال بالا آنها یک خطا با شماره #803 نمایش داده اند ولی هیچ اطلاع اضافه ای که این خطا چیست و چگونه باید با آن برخورد کرد ناده اند. Twilio دربرخود با خطاها Twilio کار بزرگی انجام داده است و علاوه بر نمایش خطا با استفاده از کد وضعیت HTTP، یک لینک برای مستندات خطا ارایه کرده است. کامنتهای افراد و بحث های پیرامون این مستندات در صفحه مربوطه یک بدنه از اطلاعات مفید در مورد این خطاها را تشکیل میدهند. SimpleGeo SimpleGeo کدهای خطا را نمایش میدهد ولی هیچ ارزش اضافه ای ندارد. چند راهکار خوب از کدهای وضعیت HTTP استفاده کنید از کدهای HTTP استفاده کنید و سعی کنید بصورت واضحی آنها را به کدهای استاندارد نگاشت کنید. بیش از 70 کد وضعیت HTTP وجود دارد. هر چند اغلب برنامه نویسان همه آنها را نمیشناسند. بنابراین اگر شما کدهای وضعیتی را که رایج نیستند مورد استفاده قرار دهید، استفاده کنندگان از API تان را مجبور میکنید از کدنویسی دست بکشند و در ویکی پدیا دنبال معنی این کد بگردند. بنابراین اکثر APIها از زیر مجموعه کوچکی از این کدها استفاده میکنند. برای مثال Google GData فقط از 10 کد وضعیت استفاده میکند؛ Netflix از 9 و Digg فقط 8 کد. Google GData 200 201 304 400 401 403 404 409 410 500 Netflix 200 201 304 400 401 403 404 412 500 Dig 200 400 401 403 404 410 500 503 شما باید از چند کد وضعیت در API خود استفاده کنید؟ در واقع اگر دقیق شویم فقط 3 نوع خروجی در هنگام تعامل بین یک برنامه و یک API میتواند وجود داشته باشد: همه چیز بدرستی کار میکند - success برنامه چیزی را درست انجام نمیدهد - client error API کاری را اشتباه انجام میدهد - server error با به کاربردن 3 کد زیر شروع کنید. اگر نیازتان برطرف نشد به آنها اضافه کنید. اما هرکز از 8 کد فراتر نروید. 200-OK 400- Bad Request 500- Internal Server Error اگر با کاهش تمام خطاهای خود به 3 خطا احساس راحتی نمیکنید میتوانید از بین 5 کد زیر به خطاهای خود اضافه کنید: 201- Created 304- Not Modified 404- Not Found 401- Unauthorized 403- Forbidden این مهم است که کدی که برگردانده میشود بتواند در منطق برنامه استفاده شود. تا جایی که میتوانید پیغام های API مفصل و تشریحی باشند. خلاصه : شرح دهید و از زبان ساده استفاده کنید. هر چقدر میتوانید در مورد علت خطای بوجود آمده توضیحات ارایه کنید. شدیدا ارایه یک لینک به مستندات خطا همانند آنچه Twilio انجام داده است را پیشنهاد میکنیم. نکاتی در مورد نسخه گذاری نسخه گذاری یکی از مهمترین مفروضات طراحی API می باشد. هرگز API ای را بدون یک شماره نسخه منتشر نکنید و نسخه را در API خود اجباری کنید. اجازه دهید به متد سه فراهم کننده API برتر نگاهی بیندازیم. Twilio /2010-04-01/Accounts/ salesforce.com /services/data/v20.0/sobjects/Account Facbook ?v=1.0 Twilio از برچسب تاریخ در آدرس خود استفاده میکند. در زمان کمپایل برنامه نویس برچسب زمان را در کد خود وارد میکند. این برچسب زمان در تمام درخواستهای HTTP استفاده میشود. وقتی که درخواست میرسد، Twilio یک جستجو انجام میدهد. براساس برچسب تاریخ مشخص میکند که آیا هنوز API معتبر است و سپس درخواست به کد مناسب هدایت میشود. این راهکار بسیار هوشمندانه و جالب است هرچند ممکن است کمی پیچیده باشد. برای مثال ممکن است فهمیدن اینکه برچسب تاریخ مربوط به زمان کمپایل کردن است یا مربوط به زمان انتشار API ممکن است مبهم باشد. Salesforce.com از v20.0 در میانه آدرس استفاده میکند. ما از بکاربردن حرف V استقبال میکنیم. هرچند از .0 خوشمان نمی آید، زیرا نشاندهنده این است که رابط ممکن است در طول زمان به دفعات مورد تغییر قرار گیرد. منطق پشت رابط ممکن است بسرعت تغییر کند اما خود رابط نباید مرتبا تغییر کند. Facebook هم از علامت V استفاده میکند اما از ورژن به عنوان یک پارامتر اختیاری استفاده میکند. این کار مشکل زا خواهد بود زیرا به محض اینکه Facebook نسخه جدید API خود را منتشر کند، تمام برنامه هایی که از شماره ورژن استفاده نمیکردند دچار مشکل خواهند شد و مجبور خواهند شد دوباره شماره ورژن را استفاده کنند. چگونه در مورد شماره های نسخه به صورت اجباری همراه با REST فکر کنیم؟ هرگز API  ای را بدون شماره نسخه منتشر نکنید. همچنین استفاده از ورژن را اجباری کنید. از پیشوند V در ورژن استفاده کنید. تا جایی که میتوانید شماره ورژن را بالاترین وحله آدرس بکار ببرید(/v1/dogs). از یک عدد صحیح ساده استفاده کنید. از ممیز مثل v1.2 استفاده نکنید. زیرا این نوع شماره گذاری به درستی کار نمیکند. شما در حال پیاده سازی یک رابط هستید نه یک برنامه.  تاچند نسخه باید پشتیبانی شود؟ حداقل از یک نسخه قبلی پشتیبانی کنید. یک ورژن را تا چه زمانی باید حفظ کرد؟ قبل از انقضای یک نسخه به برنامه نویسان اجازه دهید تا یک دوره زمانی از آن استفاده کنند. گاهی اوقات 6 ماه و گاهی اوقات تا 2 سال. این به پلتفرم توسعه دهندگان، نوع برنامه و کاربران آن بستگی دارد. برای مثال، برنامه های موبایل دوره های زمانی طولانی تری نسبت به برنامه های وب دارند. آیا شماره ورژن و فرمت باید در آدرس باشد یا در هدرها؟ اندیشه های مختلفی در مورد استفاده از  شماره ورژن در هدر وجود دارد. گاهی اوقات افراد برای گذاشتن شماره ورژن در هدر مجبور میشوند زیرا چندین API بطور داخلی وابسته دارند. این اغلب نشانه ای از یک مشکل بزرگتر است، بطور مشخص معمولا نشانه استفاده از ارتباطات داخلی بجای استفاده از یک API ساده قابل استفاده است. این به این معنا نیست که استفاده از شماره ورژن در هدر نشانه طراحی یک API مشکل دارد است. درواقع به دلایل زیادی استفاده از ورژن در هدرها صحیح تر است: از استاندارهای موجود HTTP پیروی میکند، با روح (Fielding’s vision) سازگار است، بسیاری از مسایل مربط به API های داخلی را حل میکند و غیره … . هر چند به نظر دلیل عدم استفاده API های محبوب از هدرها این است که تغییر و هک آن در browser مشکل می باشد. قواعد ساده ای که ما پیروی میکنیم : اگر منطق اداره کردن پاسخ برای درخواست API تغییر میکند آن را در داخل آدرس قراردهید تا براحتی دیده شود. اگر برای هر درخواست منطق تغییر نمیکند مانند اطلاعات OAuth آن را در هدر قرار دهید. اینها مثالهایی هستند که منبع یکسانی را نشان میدهند : dogs/1 Content-Type:application/json dogs/1 Content-Type:application/xml dogs/1 Content-Type:application/png کدی که برای هندل کردن پاسخها خواهیم نوشت در هر مورد بسیار متفاوت خواهد بود. در این مورد که استفاده از هدر صحیح تر است بحثی نیست و این همچنان یک طراحی API قوی می باشد. صفحه بندی و پاسخ جزیی پاسخ جزیی به شما اجازه میدهد تا به برنامه نویسان فقط اطلاعاتی که نیاز دارند را بدهید. مثالی در مورد درخواست یک توییت در API تویتر خواهیم زد. شما اطلاعات بسیار بیشتری از آنچه یک برنامه معمولی توییتر میخواهد از API آنها دریافت میکنید،  مثل نام شخص، متن توییت، برچسب زمان، تعداد دفعات توییت مجدد و متاداده فراوان. اجازه دهید به چندین API سرآمد که به برنامه نویسان اجازه استفاده از اطلاعات مورد نیازشان را میدهند شامل گوگل که در ایده پاسخ جزیی پیشتاز است نگاهی بیاندازیم. LinkedIn /people:(id,first-name,last-name,industry) این درخواست id، نام و نام خانوادگی و همچنین زمینه کاری شخص را برمیگرداند. LinkedIn این انتخاب گزینشی را بر اساس این نحو ساده خود-توصیف انجام میدهد. به علاوه این برای یک برنامه نویس مشکل است معنی را با استفاده از موتور جستجو مهندسی معکوس کند. Facebook  /Joe.smith/friends?fields=id,name,picture Google ?fields=title,media:group(media:thumbnail) گوگل و فیسبوک رهیافت مشابهی دارند که خوب هم کار میکند. آنها هر کدام یک پارامتر اختیاری بنام fields دارند که بعد از آن شما میتوانید نام فیلدهایی که را نیاز دارید بکارببرید. همانطور که مشاهده کردید، شما میتوانید همچنین زیراشیایی را در پاسخ قرار دهید تا اطلاعات دیگری را از منابع اضافی دریافت نمایید. فیلدهای اختیاری را در یک لیست جدا شده با کاما قرار دهید رهیافت گوگل بسیار خوب کار میکند. اینجا می بینید که چگونه میتوانیم با این رهیافت سکهای مورد نیازمان را از API استخراج کنیم: /dogs?fields=name,color,location این رهیافت برای خواندن ساده است و یک برنامه نویس میتواند فقط اطلاعاتی که به آن نیاز دارد را انتخاب  نماید. این روش مشکلات پهنای باند را که برای برنامه های موبایل مهم است با کم کردن تعداد تقاضاهای مورد نیاز ، کم میکند. صفحه بندی داده ها را در پایگاه داده برای برنامه نویس راحت کنید. این همیشه ایده بدی است که تمام منابع یک پایگاه داده را برگردانید. اجازه دهید نگاهی به نحوه مدیریت صفحه بندی در Facebook, Twitter و LinkedIn بیاندازیم. فیسبوک از offset و limit استفاده میکند. تویتر از page و rpp ( رکورد در صفحه ) و لینکدین از start و count استفاده میکند. از نظر ماهوی فیسبوک و لینکدین از روش یکسانی استفاده میکنند.  برای گرفتن رکوردهای 50 تا 75 از هر سیستم ما از دستورات زیر استفاده میکنیم : Facebook - offset 50 and limit 25 Twitter - page 3 and rpp 25 LinkedIn - start 50 and count 25 از limit و offset استفاده کنید. ما استفاده از limit و offset را پیشنهاد میکنیم. این روش رایجتر است و در بین دیتابیسهای مطرح بهتر شناخته میشود و برای برنامه نویسان استفاده از آن راحت تر است. /dogs?limit=25&offset=50 فراداده استفاده از متاداده را با هر پاسخی که صفحه بندی شده است را پیشنهاد میکنیم که در آن تعداد کل رکوردهای قابل دسترسی به برنامه نویس ارایه شود. پیش فرضها چه ؟ قانون ضعیف ما در مورد صفحه بندی پیشفرض limit=10 و offset=0 است. البته که این پیشفرضها به حجم داده های شما بستگی دارند. اگر منابع شما بزرگ است ممکن است بخواهید limit را کمتر از 10 در نظر بگیرید. اگر منابع کوچک باشند ممکن است استفاده از یک limit بزرگتر استفاده میکنیم. بطور خلاصه: از پاسخ گزینشی بوسیله فیلدهای اختیاری در یک لیست جدا شده با کاما پشتیبانی کنید. از limit و offset برای صفحه بندی راحت استفاده کنید. منابع؟ فراخوانی های API که درپاسخ چیزی غیر از منابع ارسال میکنند بسته به حوزه کار نرم افزار، چندان متداول نیستند. آنها معمولا در حوزه سرویسهای اقتصادی، مخابراتی وغیره دیده میشوند. افعالی مانند آنچه در زیر می آید ممکن است در پاسخ خود به منابع ارتباطی نداشته باشند. Calculate Ttranslate Convert برای مثال وقتی میخواهید یک محاسبه ساده الگوریتمیک مانند میزان مالیات پرداختی، یا میخواهید یک ترجمه انجام دهید و یا یک واحد پولی را به واحد دیگر تبدیل کنید، هیچ کدام نیاز برگرداندن منابع از دیتابیس ندارند.  در این گونه موارد: از افعال استفاده کنید نه اسمها برای مثال؛ یک API که 100 یورو را به ین چینی تبدیل میکند: /convert?from=EUR&to=CNY&amount=100 در مستندات API خود بصورت واضح این سناریوهای متفاوت را مشخص کنید.خیلی ساده بخشی از مستندات خود را بصورت مجزا به مواردی که محاسباتی هستند و نیاز به برگرداندن منابع ندارند اختصاص دهید. پشتیبانی از فرمتهای مختلف پیشنهاد میکنیم که بیش از یک فرمت را پشتیبانی کنید که در آن داده های خروجیتان با یک فرمت باشد ولی هر چند فرمت ورودی که نیاز باشد قبول کنید. خیلی وقت ها میتوانید فرآیند نگاشت از یک فرمت به فرمت دیگر را مکانیزه کنید.  در اینجا چندین نحو در مورد فرمت در برخی از API های کلیدی را مشاهده میکنید: Google Data ?alt=json Faoursquare /venue.json Digg* Accept:application/json ?type=json *آرگومان type در صورتی که ارسال شود مقدار هدر را بازنگاری میکند.  Digg به شما دو انتخاب میدهد: در یک متد کاملا مبتنی بر REST  محض از هدر استفاده میکند و یا در متد دیگر از پارامتر type در آدرس استفاده میکند. این میتوان گیج کننده باشد، و حتی الامکان شما باید برای جلوگیری از ابهام مستندات کامل ارایه کنید. ما راهکار Foursquare را پیشنهاد میکنیم. برای دریافت فرمت JSON از یک مجموعه یا یک عنصر خاص: dogs.json /dogs/1234.json برنامه نویسان و حتی کاربران عادی هر سیستم عامل با این نحو نقطه گذاری آشنا هستند. این روش فقط به یک کاراکتر اضافی نیاز دارد. در مورد فرمت های پیش فرض چه؟ به نظر من، JSON برنده فرمتهای پیش فرض است. JSON نزدیک چیز به زبان عمومی است. حتی اگر پس زمینه سیستم با رابی، PHP، java و پایتون و یا غیره ساخته شده باشد، بیشتر پروژه ها در پیش زمینه از جاوااسکریپت استفاده میکنند. همچنین این فرمت مزیت مختصر بودن را نسبت به ‌XML دارد. در مورد اسم ویژگیها چه؟ تا بحال در مورد فرمتها، پشتیبانی از چندین فرمت و کار با JSON به عنوان فرمت پیشفرض صحبت کردیم. این بار میخواهیم در مورد آنچه که در پاسخ برگردانده میشود صحبت کنیم. شما یک شی با صفات داده در آن دارید. چگونه باید آنها را نامگذاری کنید؟ در اینجا چندین پاسخ APIاز API های پیشتاز را می بینیم:

Twitter “created_at”:”Thu Nov 03 05:19;38 +0000 2011” Bing “DateTime”:2011-10-29T09:335:0Z” Foursquare “createdAt”:1320296464 هر کدام از آنها از قرارداد کد نویسی متفاوتی استفاده میکنند. هر چند رهیافت Twitter برای من به عنوان یک توسعه دهنده Ruby on Rails آشناتر است، اما از نظر ما رهیافت Foursquare از بقیه بهتر است. پاسخ API چگونه در کد استفاده میشود؟ شما پاسخ را Parse میکنید. آنچه که برمیگردد یک شی را مقداردهی میکند. چیزی شبیه این : var myObject=JSON.parse(response); اگر شما از رهیافت Bing و Twitter استفاده کنید، کد شما مشابه خواهد  بود.  پیشنهاد ها: از JSON به عنوان فرمت پیشفرض استفاده کنید. از نحو جاوااسکریپت برای نامگذاری صفات استفاده کنید. از حروف بزرگ به عنوان جدا کننده استفاده کنید(CamelCase) از حروف بزرگ یا کوچک بسته به نوع شی استفاده کنید. این هیافت منجر به این میشود که کد شما چیزی شبیه آنچه در زیر می آید میشود: “createdAt”:13320296464 timing=myObject.createdAt; نکاتی در مورد جستجو در حالیکه یک جستجوی ساده با یک API مبتنی بر منابع به سادگی میتواند مدل شود، جستجوی پیچیده تر در میان منابع مختلف نیاز به طرحی متفاوت دارد. اگر میخواهید یک جستجوی کلی در میان منابع انجام دهید ما استفاده از مدل گوگل را پیشنهاد میکنیم: Global search /search?q=fluffy+fur در اینجا search یک فعل است و ?q کوئری را ارایه میدهد. Scoped search برای اضافه کردن وحله به جستجوی خود، میتوانید وحله خود را به ابتدای جستجو بیافزایید. برای مثال جستجوی سگهایی که صاحبشان دارای ID 5678 می باشد: /owners/5678/dogs?q=fluffy+fur دقت کنید که ما از عبارت search را بصورت مصرح بکار نبردیم و از پارامتر q برای نمایش جستجوی وحله ای استفاده کرده ایم. نتایج فرمت بندی شده برای جستجوی هریک از پاسخهای مبتنی بر فعل، میتوانید فرمت را بصورت زیر اضافه کنید /search.xml?q=fluffy+fur تحکیم درخواستهای API در یک زیردامنه تا بحال در مورد چیزهایی که بعد از بالاترین سطح دامنه می آمدند صحبت کردیم. این بار نوبت به چیزهایی میرسد که در آنسوی آدرس قرار دارد. نحوه عمل فیسبوک، فوراسکور و تویتر را بررسی میکنیم: فیس بوک از دو API استفاده میکند. آنها با api.facebook.com شروع کردند و در ادامه آن را حول محور گراف اجتماعی به graph.facebook.com تغییر دادند.  graph.facebook.com  api.facebook.com  فوراسکور فقط یک API دارد.  api.foursquare.com  تویتر سه APIدارد. دو تا از آنها بر جستجو و استریمینگ متمرکز شده اند. stream.twitter.com search.twitter.com api.twitter.com فهم اینکه چگونه فیسبوک و توییتر به چیزی بیشتر از یک API رسیده اند ساده است. با گذشت زمان و اقتضای کسب و کار کارهای زیادی انجام میشود و همچنین تنظیم یک ‌مدخل CName در DNS شما برای اینکه تقاضاها را به کلاسترهای متفاوت ارسال کند کار ساده ایست. اما اگر ما درحال تصمیم گیری باشیم و همچنین علاقه برنامه نویسان را در نظر داشته باشیم، پیروی از Foursquare را پیشنهاد میکنیم:  تمام درخواستهای API را در یک زیر دامنه قرار دهید. این برای برنامه نویسانی که میخواهند برنامه های جالبی با استفاده از API شما بسازند، تمیزتر راحتر و واضح تر خواهد بود. همچنین فیسبوک، فوراسکور و توئیتر همگی پورتالهایی مختص توسعه دهندگان دارند.  developers.facebook.com  developers.foursquare.com  dve.twitter.com  چگونه همه اینها را سازماندهی کنیم؟ دروازه API شما باید یک دامنه سطح اول باشد. برای مثال api.teachdogrest.com. همگام با حفظ روح REST، پورتال توسعه دهندگان شما باید از این الگو پیروی کند: developers.yourtopleveldomain. برای مثال developers.teachdogrest.com از redirect استفاده کنید. اگر از درخواستهایی که برنامه نویسان به API‌ ارسال میکنند احساس میکنید که باید به بخش خاصی هدایت شوند میتوانید از redirect استفاده کنید. فرض کنید برنامه نویس در مرورگر خود عبارت api.teachdogrest.com‌ را تایپ میکند اما هیچ اطلاعاتی برای درخواست GET وجود ندارد، احتمالا میتوانید کاربر را به سمت پورتال برنامه نویسان هدایت کنید.

api->developers dev->developers developer->developers نکاتی برای مدیریت استثناها تا اینجا در مورد خط اصلی و رفتارهای استاندارد بحث کرده ایم. در اینجا برخی از استانات را کاربر API ما نمیتواند اداره کند بررسی میکنیم. برای مثال گاهی اوقات مشتریان API نمیتوانند کدهای HTTP را تفسیر کنند و یا تعداد محدودی از این کدها را پشتیبانی میکنند. راههای مدیریت چنین موقعیتهایی و همچنین محدودیتهای که برخی از کاربران خاص API دارند چیست؟ وقتی که مشتری کدهای خطای HTTP را رد میکند این در میان ورژنهای مختلف Adobe Flash معمول است که اگر شما هر کد HTTP به غیر از کد 200 در پاسخ به آن ارسال کنید، Flash آن پاسخ را رد میکند و کد خطا را به کاربرنهایی در برنامه نشان میدهد. بنابراین توسعه دهنده برنامه فرصت رد کردن کد خطا را نخواهد داشت. توسعه دهندگان نیاز دارند تا API به طریقی این مورد را پشتیبانی کند. Twitter این کار را به صورت عالی انجام میدهد. آنها یک پارامتر اختیاری بنام suppress_response_codes دارند. اگر این پارامتر با مقدار true مقداردهی شود پاسخ HTTP همیشه کد 200 خواهد بود. /public_timelines.json?suppress_respnse_codes=true HTTP satus code: 200 {“error”:”Could not authenticate you.”} توجه کنید که این پارامتر طول زیادی دارد و آنها میتوانستند از پارامتر کوچکتری مثل src استفاده کنند ولی ترجیح داده اند که از یک پارامتر طولانی و واضح استفاده کنند. پیشنهادات کلی : از suppress_response_codes=true استفاده کنید. کد HTTP دیگر فقط برای کد نیست قوانین مدیریت خطاها از فصل پیش را تغییر دادیم. در این مبحث کد HTTP دیگر فقط مختص کد نیست و میتواند در نظر گرفته نشود و مشتریان برنامه نیاز نیست که هرگز کد HTTP را چک کنند، چرا که این کد همیشه یکسان است. هر کد پاسخ HTTP را که باید داشته باشیم را در پیغام ارسالی قرار دهید. در مثال زیر کد پاسخ 401 است. شما میتوانید آن را در پیغام پاسخ ببینید. بعلاوه این پاسخ شامل کدهای خطای اضافی و اطلاعات مفصل در پیغام میشود. Always return OK /dogs?suppress_response_codes=true Code for ignoring 200 -OK Message for people & code {“response_code”:401,”message”:”Verbose, plain language description of the problem with hints about how to fix it.” “more_info”:”http://dev.tecachdogrest.com/errors/12345”,”code”:12345} هنگامی که مشتری فقط از متدهای محدود HTTP پشتیبانی میکند خیلی وقتها ممکن است که مشتری API فقط از متدهای POST , GET پشتیبانی کند و از متدهای PUT و DELETE پشتیبانی نکند. برای اینکه یکپارچگی متدهای چهارگانه HTTP را حفظ کنید ما استفاده از متدی که توسعه دهندگان Ruby on Rails بکار میبرند را پیشنهاد میکنیم: متد را یک قسمت اختیاری از آدرس قرار دهید. به اینصورت که فعل HTTP همیشه GET باشد ولی برنامه نویس بتواند متدهای محض HTTP را در آدرس استفاده کند و یک API تمیز RESTful داشته باشیم. Create /dogs?method=post Read /dogs Update /dogs/1234?method=put&location=park Delete /dogs/1234?method=delete اخطار :‌استفاده از متد ‌GET برای این کاربرد میتواند خطرناک باشد زیرا اگر آدرس در یک صفحه وب قرار گیرد خزنده هایی مثل Googlebot میتوانند بصورت ناآگاهانه محتوایی را خراب کنند یا از بین ببرند. از نحوه پیاده سازی این قابلیت در برنامه خود آگاهی کامل داشته باشید. احراز هویت (authentication) بحث زیادی در مورد احراز هویت وجود دارد. من و همکارانم در Apigee کاملا با هم در مورد نحوه مدیریت احراز هویت هم عقیده نیستیم. به هر حال آنچه در ادامه می آید نظر من است. اجازه دهید به سه سرویس پیشرو نگاهی بیاندازیم و ببینیم که هر کدام از آنها چگونه به صورت متفاوتی احراز هویت کاربران را مدیریت میکنند. PyaPal Permissions Service API Facebook OAuth 2.0 Twitter OAuth 1.0a در نظر داشته باشید که API اختصاصی PyaPal مدتها قبل از OAuth وجود داشته است. شما باید چه کنید؟ از آخرین و بزرگترین OAuth استفاده کنید ( در زمان نوشتن این مطلب OAuth 2.0). این بدین معناست که برنامه های وب یا موبایل که از API استفاده میکنند نیاز به اشتراک گذاری پسوردها ندارند. این به فراهم آورنده API اجازه میدهد که برای کاربران انفرادی در کل برنامه بدون اینکه نیاز باشد کاربر پسورد خود را عوض کند از توکن ها استفاده کنند. این در هنگامی که یک برنامه موبایل مورد تهاجم قرار میگیرد و یا یک برنامه خرابکار تشخیص داده میشود مهم است. در کل، OAuth 2.0 به معنی امنیت بیشتر و تجربه کاربری بهتر برای کاربران وب و موبایل است. از چیزهایی شبیه OAuth ولی متفاوت با آن استفاده نکنید. برای برنامه نویسان ناخوشایند خواهد بود اگر از کتابخانه OAuth در زبان برنامه نویسی خود بخاطر نسخه متفاوت شما نتوانند استفاده کنند. تقاضاها از API شما اجازه دهید نگاهی به چند درخواست و پاسخ از API فرضی خود نگاهی بیاندازیم. Create a brown dog named Al POST /dogs name=Al&furColor=brown Response 200 OK { “dog”:{ “id”:”1234”, “name”:”Al”, “furColor”:”brown”} } Rename Al to Rover - Update PUT /dogs/1234 name=Rover Response 200 OK

{ “dog”:{ “id”:”1234”, “name”:”Rover”, “furColor”:”brown”} } Tell me about a particular dog GET /dogs/1234 Response 

200 OK

{ “dog”:{ “id”:”1234”, “name”:”Rover”, “furColor”:”brown”} } Tell me about all the dogs Get /dogs Response

200 OK

{ “dogs”:[{ “dog’:{ “id”:”1233”, “name”:”Fido”, “furColor”:”white”}},

{“dog”:{

“id”:”1234”, “name”:”Rover”, “furColor”:”brown”} }}]

“_metadata”: [{“totalCount”:327,”limit”:25,”offset”:100}] } Delete Rover :-( DELETE /dogs/1234 Response 200 OK API های شلوغ بیایید به برنامه نویسانی که از API ما استفاده خواهند کرد فکر کنیم. نحوه استفاده برنامه نویسان از API خود را تصور کنید. هنگام طراحی API و منابع خود، سعی کنید تصور کنید که برنامه نویسان از آن برای ساخت یک رابط کاربری، یک برنامه iPhone و یا برنامه های دیگر استفاده خواهند کرد. برخی از طراحی های API بسیار شلوغ هستند. به این معنی که برای ساخت یک برنامه یا UI ساده باید تعداد بسیاری زیادی فراخوانی API  به سرور داشته باشید. تیم طراحی API گاهی میتواند تصمیم بگیرد که بجای ساختن یک API مبتنی بر منبع RESTful فقط از 3 یا 4 متد getter , setter به شیوه جاوا برای یک رابط کاربری خاص استفاده کند. ما این را پیشنهاد نمیکنیم. میتوانید یک RESTful API طراحی کنید و همچنان از شلوغی پرهیز کنید. کاملاRESTful باشید اما میانبرهایی ایجاد کنید ابتدا API و منابع خود را براساس اصول طراحی RESTful طراحی کنید و سپس میانبرهایی ایجاد نمایید. کدام نوع میانبرها؟ این را در نظر بگیرید که 80 درصد از تمام برنامه های شما به برخی از ترکیبها در پاسخ نیازمند هستند، سپس انواع تقاضا برای آنچه نیاز دارند را طراحی کنید. فقط به یاد داشته باشید که ابتدا مورد اول را انجام دهید یعنی طراحی کاملا RESTful. از مزایای نحو پاسخ جزیی استفاده کنید. نحو پاسخ جزیی که در بخش قبلی بحث شد میتواند کمک کند. برای جلوگیری از ایجاد آدرسهای پایه غیر تکی میتوانید از شیوه پاسخ جزیی استفاده کنید تا  منابع مستقل و وابسته را ارایه دهید. در مورد مثال API سگ، سگها با صاحبان خود که آنها نیز با دامپزشکان رابطه داشتند. از جاسازی پاسخ جزیی با استفاده از علامت نقطه استفاده کنید و فقط اطلاعاتی را که نیاز است برگردانید. /owners/5678?fields=name,dogs.name ارایه یک SDK این سوال رایجی برای فراهم آوردندگان API است - آیا نیاز است که برای API خود SDK و کتابخانه کد فراهم کنیم؟ اگر API شما از نمونه های خوب طراحی استفاده میکند، خود شمول، مبتنی بر استاندارد و خوب مستند شده است، برنامه نویسان میتوانند بدون نیاز به SDK جداگانه از آن استفاده کنند. البته استفاده از نمونه کدهای خوب مستند شده کاملا ضروری است. اما در سوی دیگر اگر درست کردن یک رابط کاربری به اطلاعات زیادی در مورد حوزه عملکرد نرم افزار نیاز داشته باشد چه؟ این میتواند حتی برای برنامه نویسانی که بر روی یک UI یا برنامه روی یک API با حوزه عمل بسیار ساده کار میکنند مسئله چالش انگیزی باشد. برای مثال Twitter را با موضوع اولیه آن یک پیغام 140 کاراکتری در نظر بگیرید. شما نباید برای غلبه بر مشکل اطلاعات در مورد حوزه برنامه، API  خود را تغییر دهید. بجای آن میتوانید API خود را با کتابخانه های کد و کیتهای توسعه نرم افزار(SDK) پشتیبانی کنید. در اینصورت دیگر نیازی نیست که طراحی API خود را سنگین کنید. اغلب بیشتر آنچه که نیاز است در سمت مشتری انجام میپذیرد و شما میتوانید آن را به SDK تحمیل کنید. SDK میتواند کد ویژه پلتفرم (platform-specific) فراهم کد که برنامه نویسان در برنامه های خود از آن استفاده نمایند و شما API خود را تمیز نگه دارید. دلایل دیگری که میتوانند باعث شوند تا یک SDK برای API خود ایجاد کنید عبارتند از: تطبیق پذیری سریع با یک پلتفرم خاص. ( برای مثال Objective C SDK برای iPhone) بسیاری از برنامه نویسان با تجربه فقط با Objectve C کار میکنند بنابراین یک SDK میتواند مفید واقع شود. سختی تجمیع برای کارکردن با API خود را کم کنید اگر موارد استفاده کلیدی از API پیچیده هستند و یا نیازدارند که با استاندار خاصی در سمت مشتری انجام شوند میتوانید از SDK استفاده کنید. یک SDK میتواند کد بد یا غیر ضروری (که میتواند باعث کاهش سرعت سرویس شود) را کاهش دهد به عنوان یک منبع برنامه نویس SDK های خوب نیروی اجباری برای سورس کد خوب و مستندات هستند. yahoo و Paypal مثالهای خوبی هستند: Yahoo! http://developer.yahoo.com/social/sdk Pyapal https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&_ID=developer/library_download_sdks برای فروش API خود به گروهی خاص شما SDK خود را به صفحه پلاگین یا مثالهای یک جامعه موجود برنامه نویسان یک پلتفرم خاص آپلود میکنید. الگوی طراحی API Facade حالا که به نقطه رسیدیم ممکن است از خود بپرسید از منظر معماری چگونه باید بیاندیشیدیم؟ چگونه میتوانیم تمام این الگوهای عملی را بکارببریم و سرویسها و سیستمهای داخلی را طوری برای برنامه نویسان ارایه دهیم که همچنان یک API قابل تکرار و نگهداری داشته باشیم؟ سیستمهای پشت صحنه موجود اغلب برای ارایه مستقیم به توسعه دهندگان بسیار پیچیده هستند. آنها پایدار و قابل اتکا هستند اما اغلب برپایه تکنولوژیهای قدیمی می باشند و همیشه قابل ارایه بصورت استاندارهای وب مثل HTTP نیستند. همچنین این سیستمها میتوانند ارتباطات داخلی پیچیده ای داشته باشند که به آرامی تغییر میکنند و این بدین معناست که نمیتوانند به سرعت به نیازی در حال تغییر توسعه دهندگان برنامه های موبایل پاسخ دهند. در واقع، مسئله طراحی یک API برای یک سیستم بزرگ نیست بلکه مسئله طراحی API برای آرایه ای از سیستمهای مکمل می باشد که همگی نیاز دارند API ارزشمندی را به توسعه دهنده ارایه دهند. مفید خواهد بود که درباره چند ضد الگو که دیده ایم صحبت کنیم. اجازه دهید با هم علت اینکه از نظر ما این الگو جواب نمیدهند را بررسی کنیم. رهیافت Build Up برنامه نویس اجزای اصلی یک سیستم بزرگ را میسازد و لایه تجزیه کننده XML بر روی آن ارایه میکند. این رهیافت از آن جهت که میتواند به سرعت در ورژن 1 فروخته شود شاید ارزشمند باشد. همچنین تیم API شما درک مشترکی از سیستم دارند. اما جزییات سیستم داخلی در وحله اشیا داخلی کاملا مستحکم شده اند و میتوانند برای توسعه دهندگان خارجی مبهم باشند. همچنین شما در حال ارایه جزئیات معماری داخلی خود هستید که به ندرت میتواند ایده خوبی باشد. این رهیافت میتواند انعطاف پذیر باشد زیر شما یک نگاشت یک به یک از آن چه که سیستم انجام میدهد به آنچه که به API ارایه میدهد دارید. بطور خلاصه ساخت یک سیستم از رکوردها به یک API میتواند باعث افزایش پیچیدگی شود. رهیافت کمیته استانداردها اغلب سیستمهای داخلی صاحبان متفاوتی دارند و به وسیله افراد مختلفیار اداره میشود که دیدگاههای متفاوتی در مورد اینکه سیستم باید چگونه کارکند، دارند. طراحی یک API به وسیله کمیته استانداردها اغلب شامل ایجاد سند استانداردها میشود که طرح و آدرسها و چنین چیزهایی را مشخص میکند. تمام توسعه دهندگان براساس آن هدف مشترک کار میکنند. از مزیتهای این رهیافت این است که به سرعت ورژن یک را ایجاد میکنید. همچنین میتوانید روح واحدی را در میان تمام سازمان احساس کنید و استراتژی مشخصی داشته باشید که در یک سازمان بزرگ با همکاران و شرکای متعدد میتواند بسیار مفید واقع شود. از معایب این رهیافت آن است که میتواند بسیار  کند شود. حتی اگر شما سند را بسیار سریع آماده کرده باشید، مجبور کردن همه به اینکه آن را پیاده سازی کنند میتواند بسیار کند باشد. همچنین به علت تعداد زیاد توافقات و تعهدات این رهیافت میتواند باعث ایجاد یک طراحی متوسط شود. رهیافت Copy Cat این روش را گاهی در شرکتهایی که از بازار عقب افتاده اند میبینیم. برای مثال وقتی رقیب اصلی آنها یک راه حل معرفی کرده است. در این رهیافت نیز شما به سرعت ورژن یک را ارایه میکند و یک منحنی سازگاری سریع با برنامه نویسان به علت آشنا بودن آنها با API رقیب دارید. هر چند ممکن است شما با یک محصول نا متمایز که در بازار API ها به عنوان یک پیشنهاد نامرغوب شناخته شود کار را تمام کنید. اما در واقع شما از ارایه ارزشهای کلیدی خود و تمایز با دیگران به علت کپی برداری از API دیگران باز میمانید. راه حل  - الگوی API facade بهترین راه حل با تفکر در مورد اساس مدیریت تولید شروع میشود. محصول شما ( API شما) باید معتبر، کاربردی و متمایز باشد. مدیر تولید شما یک عضو کلیدی از تیم API شماست. بعد از اینکه مدیر تولید تصمیم گرفت که تصویر بزرگ باید چگونه باشد نوبت به معماران میرسد. ما پیشنهاد میکنیم که از الگوی API facde استفاده کنید. این الگو یک لایه مجازی بین رابط در بالا و پیاده سازی API در پایین میدهد. شما در واقع یک نما (facade) از آنچه که باید API شما از دید یک برنامه نویس به نظر برسد ایجاد میکنید. برنامه نویس و برنامه ای که از API استفاده میکنند در بالا قرار میگیرند. API facade برنامه نویس و برنامه را از API جدا میکند. یک طراحی تمیز در facde به شما اجازه میدهد یک مسئله بسیار سخت را به چند مسئله ساده تر تقسیم کنید. “از الگوی facde وقتی استفاده کنید که میخواهید یک رابط ساده برای یک زیرسیستم پیچیده ایجاد کنید. زیر سیستمها اغلب از سیستمی که در آن قرار دارند پیچیده تر هستند.” پیاده سازی یک الگوی API facade از سه گام اساسی تشکیل میشود. API ایده آل خود را طراحی کنید. آدرسها، پارامترهای درخواست و پاسخ، هدرها و غیره را طراحی کنید. طراحی را با داده ها پیاده سازی کنید. این توسعه دهندگان برنامه اجازه میدهد که از API شما استفاده کنند و به شما بازخورد بدهند حتی قبل از اینکه API به سیستمهای داخلی متصل گردد. بین سیستمهای داخلی و facade ارتباط برقرار کنید. استفاده از این الگو مسئله بزرگ شما را به سه مسئله کوچک تقسیم میکند. اگر تلاش کنید که یک مشکل بزرگ را حل کنید، آنگاه با  کدنویسی شروع خواهید کرد و تلاش  خواهید کرد که با منطق تجاری  خود را روی یک API تمیز بسازید. احتمالا اشیا، جدولها، فیدهای RSS و غیره را از مخازن خود ارایه خواهید کرد که به XML نگاشت شده اند قبل از اینکه به فرمت قابل استفاده در برنامه ارایه شوند. این رهیافت یک رهیافت ماشین به ماشین متمرکز بر برنامه می باشد و درست انجام دادن آن مشکل است. استفاده از الگوی facade برای عبور از رهیافت مخزن به شما کمک خواهد کرد. ابتدا میتوانید با حول هر یک از مراحل سه گانه جداگانه مانور دهید و افرادی داشته باشید که به صورت واضح رهیافت عملگرای شما را در می یابند. دوما مسیر حرکت از سمت برنامه به سمت توسعه دهنده تغییر میکند و هدف این میشود که توسعه دهنده برنامه براحتی از  API شما استفاده کند. facade به علت جایی از معماری که در آن قرار میگیرد، میتواند یک شاهراه عالی باشد. حالا شما میتوانید از facade برای پیاده سازی الگوهای رایج (برای صفحه بندی، پرس و جوها، ترتیب، مرتب سازی و …)، احراز هویت، تعیین دسترسی، نسخه بندی  و غیره استفاده کنید. مزیت دیگر آن برای تیم API این است که براحتی میتواند به سناریوهای مختلف اعم از اینکه توسعه دهنده داخلی باشد، شریک تجاری باشد و یا غیره آداپته شود. تیم API میتواند با نیازهای در حال تغییر برنامه نویسان از جمله پروتکلها و زبانهای همیشه در حال تغییر حرکت کند. همچنین گسترش API با ساخت توانایی های بیشتر برنامه شما و یا اضافه کردن افزونه ها به سیستم های موجود آسانتر خواهد بود.

منبع apigee.com  

اولینی که قرار است آخرین نباشد.

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