وب سرویس !‌ RESTful API

Restful APIاین روزها به دلیل پوزیشن شغلی ای که دارم؛ شدیدا درگیر نوشتن وب سرویس و مشکلات وابسته با اون شدم . مدتها سرچ کردم که بتونم حداقل یک اصولی رو در نوشتن وب سرویس هام رعایت کنم که نه تنها خودم راحت باشم؛ بلکه برای آینده برنامه نویس هایی که به جای من میان هم احساس آرامش داشته باشن . علاوه بر این؛ برنامه نویس موبایل و یا UI که میخان با وب سرویس های من کار کنن هم راحت باشن و نفرین پشت سرم نباشه . مقالات متفاوتی خوندم؛ موارد زیادی از Best Practice ها رو خوندم که بتونم به جمع بندی درست برسم؛‌ در نتیجه تصمیم گرفتم چند مورد که واقعا به نظرم مثبت و کاربردی بود و به نوعی یک اصول قابل پذیرش برای همه هست رو مکتوب کنم و اینجا بنویسم :‌فرض رو بر این میگیریم که وظیفه ما نوشتن یک وب سرویس در زمینه کاربران سایت و پست هاشون هست . ۱ - در ساختار وب سرویستون ؛‌به موقع از متد های GET/POST/PUT/DELETE استفاده کنید . از متد GET برای خواندن اطلاعات استفاده کنید . از متد POST برای ایجاد و ثبت اطلاعات جدید استفاده کنید .متد PUT برای انجام عملیات به روز رسانی و در نهایت از DELETE هم که مشخص هست؛ برای حذف رکورد/اطلاعات . ۲ - در endpoint هاتون از افعال استفاده نکنید !‌به عنوان مثال؛ به روت های زیر دقت کنید :‌فرضا ما میخایم اطلاعات تمام کاربرها رو از وب سرویس دریافت کنیم؛ خب بهتره که به جای استفاده از [GET] /getAllUsersاز [GET] /users/استفاده کنیم؛ نه تنها زیباتر نوشتیم؛ بلکه اصولی تر نوشتیم . طبق صحبتی که قبل تر کردم ما از GET برای دریافت/نمایش استفاده میکنیم . پس برای ثبت یک کاربر جدید؛ به جای [POST] /createNewUserاز[POST] /users/استفاده میکنیم . به همین روش برای دریافت اطلاعات یک کاربر :‌[GET] /users/niman2d/برای دریافت تمام مقالات یک کاربر خاص :‌[GET] /users/niman2d/articles/برای دریافت یک مقاله خاص از کاربر مشخص ( به عنوان مثال؛ مقاله شماره ۱۲ کاربر niman2d ) :‌[GET] /users/niman2d/articles/12همونطور که مشاهده میکنید این روش خیلی ساده تر؛ خوانا تر هست و همینطور یکپارچگی رو در کل endpoint های شما حفظ میکنه . یک مثال دیگه برای این قسمت میتونه ثبت مقاله جدید برای کاربر NimaN2D باشه (‌درخواست با متد POST ارسال میشه واطلاعات لازم در بدنه درخواست پاس داده میشه ) :‌[POST] /users/niman2d/articles/ ۳ - فراش نکنید که هیچ گاه از اسم های مفرد استفاده نکنید . استفاده از اسامی مفرد اشتباه نیست؛ ولی گزینه بهتری همه وجود داره؛ به عنوان مثال :‌[GET] /user/niman2d/article/12وقتی وب سرویس رو مینویسیم و داکیومنت اون رو در اختیار برنامه نویس های دیگه قرار میدیم؛ همه متوجه منظور ما میشن؛ اما چرا روش بهتری رو پیش نگیریم که حتی بدون داکیومنت هم؛ همه بتونن متوجه روت های ما بشن ؟‌[GET] /users/niman2d/articles/12چرا خوانایی بیشتر هست ؟‌ ما ابتدای روت گفتیم به کاربرها اشاره داریم؛ در قسمت دوم اسم کاربری که نیاز داریم و در ادامه گفتیم مقالات اون کاربر و از بین اون مقالات؛ مقاله شماره ۱۲ رو نیاز داریم؛ در عین سادگی؛ قابل فهم تر بود؛نه ؟۴ - همیشه در نظر داشته باشید که وقتی میخاید اطلاعات رو به سمت کاربر برگردونید؛ پارامتر های مختلف از کاربر دریافت کنید !‌ LIMIT & OFFSET رو فراموش نکنید . با توجه به پروژه من معمولا اعداد متفاوتی رو در نظر میگیرم؛ عموما چون برای اپ موبایل استفاده میشه؛ جواب بازگشتی از وب سرویس هام محدود به ۶ مورد هست . فرضا اگر آخرین مقالات کاربر رو از وب سرویس درخواست کنند ؛ ۶ مقاله آخر رو من برگشت میدم و در صورتی که مقادیر LIMIT & OFFSET رو هم ارسال کنند ؛ طبیعتا این مقادیر با توجه به درخواست کاستومایز میشه : شش مقاله آخر کاربر با نام کاربری niman2d[GET] /users/niman2d/articlesحالا اگر برنامه نویس صلاح بدونه که بهتر هست ۱۵ مقاله آخر برگشت داده بشه؛ به سادگی به این شکل درخواستش رو ارسال میکنه : [GET] /users/niman2d/articles?limit=15و اگر باز هم صلاح بدونه که از مقاله ۵ام به بعد و تعداد ۱۵ مقاله رو از وب سرویس بگیره : [GET] /users/niman2d/articles?limit=15&offset=5مرتب سازی :‌ [GET] /users/niman2d/articles?limit=15&offset=5&orderBy=title&sort=descهیچکدوم از این موارد اجباری نیستن و برنامه نویس سمت کاربر/موبایل بسته به صلاحدیدی که داشته باشه میتونه هر یک از این موارد رو درخواست کنه. داینامیک کردن فیلد هاشاید در مواردی نیاز باشه که ما تمام فیلد ها رو برنگردونیم؛ طبق درخواست هایی که ارسال میشه این موارد رو شخصی سازی کنیم :‌[GET] /users/niman2d/articles?fields=title,description,publish_dateتمامی پروژه ها؛ بعد از تولید وارد مرحله توسعه میشن؛ پس چرا نباید ورژن بندی کنیم ؟ [GET] http://sampleSite.com/api/v1/users/niman2d/articles/۴ - مدیریت خطا هازمانی که درگیر نوشتن وب سرویس میشیم باید این رو در نظر داشته باشیم که طرف دیگر سرویس ما؛ ماشین هست نه انسان !‌ پس مدیریت خطاها به شدت مهمه ؛ فرضا وقتی یک روت اشتباها فراخوانی میشه نباید صفحه ۴۰۴ سایت نمایش داده بشه بلکه باید خطای مربوط به ۴۰۴ به همراه کد و جزییات ارسال بشه؛ یا وقتی اشتباها به جای POST ؛ روت ما با GET فراخونی میشه خطا ای مشخص برگشت داده بشه .۵ - لیست کد های HTTP را مطالعه کنید (مانند : ۲۰۰ ,۲۰۱ ,۴۰۰ ,۴۰۴ ,۵۰۰ و ... )۶ - ساختار یکپارچه !‌علاوه بر اینکه در endpoint ها یا همون route هامون داریم ساختار یکپارچه رو رعایت میکنیم؛ حتما باید در نظر داشته باشیم در زمان بازگشت دادن پاسخ ها به شکل JSON ساختار یکپارچه رو رعایت کنیم . فرضا برای برگشت دادن درخواست های موفق :‌{ "success": true, "status": 200, "data": { "username": "niman2d", "articles": 2 } }و یا برای برگشت دادن خطاها : { "success": false, "status": 400, "error": { "code": "invalid user", "message": "The requested user is invalid." } }لازم هست بگم تمام موارد نوشته شده در این مقاله؛ تنها و تنها به عنوان پیشنهاد هست و در نهایت شخصی که مهم هست شمایید و بس .و در نهایت قطعا روش های بهتری هم وجود داره و من خوشحال میشم از روشهای بهتر؛ بهینه تر و اصولی تر مطلع بشم و از شما یاد بگیرم :)