با دوره‌های رایگان فناپ‌کمپس در این روزها، کنار شما هستیم.

Articles

RESTful API چیست؟ هر آنچه باید درباره REST و API بدانید.

20 بازدید

زمان مطالعه: 14 دقیقه

وقتی یک اپلیکیشن اطلاعات دوره‌ها را از سرور می‌گیرد، کاربری ثبت‌نام می‌کند یا اطلاعات حسابش را تغییر می‌دهد، معمولاً یک API این ارتباط را مدیریت می‌کند. اما هر API که از HTTP استفاده می‌کند، RESTful نیست.

RESTful API رابطی است که براساس اصول معماری REST طراحی می‌شود. در این معماری، اطلاعات سیستم به شکل Resource (منبع) در نظر گرفته می‌شوند و برای دسترسی به هر منبع، Endpoint (آدرس مشخص برای دسترسی به منبع) تعریف می‌شود.

مثلاً در یک سایت آموزشی، «دوره» می‌تواند یک Resource باشد. آدرس /courses به مجموعه دوره‌ها اشاره کند و /courses/25 مربوط به دوره شماره ۲۵ باشد. اینکه با این آدرس چه کاری انجام شود، با متدهایی مثل GET، POST، PUT، PATCH و DELETE مشخص می‌شود.

پس برای شناخت یک RESTful API فقط دیدن آدرس‌ها کافی نیست؛ باید بدانیم منابع چطور تعریف شده‌اند، هر درخواست چه کاری انجام می‌دهد و سرور با چه پاسخی نتیجه آن را اعلام می‌کند.

RESTful API چیست؟

REST مخفف Representational State Transfer و یک سبک معماری برای طراحی ارتباط میان بخش‌های مختلف یک سیستم است. وقتی یک API براساس اصول و محدودیت‌های این معماری طراحی شود، به آن RESTful API می‌گوییم.

RESTful API

در REST، تمرکز روی «منابع» است، نه نام عملیاتی که قرار است انجام شود. مثلاً در یک سامانه آموزشی، «دوره» یک Resource (منبع) است. به‌جای اینکه برای دریافت دوره‌ها آدرسی مثل این داشته باشیم:

/getCourses

خود منبع را در آدرس قرار می‌دهیم:

/courses

حالا متد HTTP مشخص می‌کند قرار است چه کاری روی این منبع انجام شود. برای مثال، GET /courses فهرست دوره‌ها را دریافت می‌کند و POST /courses برای ایجاد یک دوره جدید به کار می‌رود. به همین دلیل، در یک API مبتنی بر REST معمولاً با آدرس‌هایی روبه‌رو هستیم که منابع را نشان می‌دهند و متدها نوع عملیات را مشخص می‌کنند.

REST و RESTful هم دقیقاً یک مفهوم نیستند. REST نام این سبک معماری است؛ RESTful به API یا سیستمی گفته می‌شود که اصول REST را در طراحی خود رعایت کرده باشد.

معماری REST؛ اصول و قواعد طراحی API

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

اصول معماری REST

Client-Server و Stateless؛ پایه‌های ارتباط در REST

در معماری Client-Server (کلاینت-سرور)، مسئولیت کلاینت و سرور از یکدیگر جداست. کلاینت درخواست را ارسال و نتیجه را نمایش یا استفاده می‌کند؛ سرور هم مسئول پردازش درخواست و ارائه اطلاعات مورد نیاز است. در نتیجه، مثلاً تغییر رابط کاربری سایت لزوماً نیازی به تغییر منطق API ندارد.

یکی از مهم‌ترین اصول REST، Stateless (بدون حالت) بودن ارتباط است. یعنی سرور نباید برای پاسخ‌دادن به درخواست جدید، به اطلاعات ذخیره‌شده از درخواست قبلی وابسته باشد. هر درخواست باید اطلاعات لازم برای پردازش خودش را همراه داشته باشد.

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

رابط یکپارچه، کش و معماری لایه‌ای در REST

Uniform Interface (رابط یکدست) یعنی شیوه ارتباط با منابع API باید تا حد امکان قابل‌پیش‌بینی باشد. اگر /courses منبع دوره‌هاست، عملیات مختلف روی آن با متدهای HTTP مشخص می‌شوند؛ نه اینکه برای هر عملیات، یک الگوی کاملاً متفاوت برای آدرس‌ها ساخته شود.

REST امکان Cache (ذخیره موقت پاسخ) را هم در نظر می‌گیرد. سرور باید مشخص کند یک پاسخ قابل ذخیره‌شدن است یا نه. اگر پاسخ قابل ذخیره باشد، کلاینت یا بخش‌های میانی می‌توانند در شرایط مناسب از نسخه ذخیره‌شده استفاده کنند و تعداد درخواست‌های تکراری به سرور کاهش پیدا کند.

در Layered System (معماری لایه‌ای) نیز کلاینت لازم نیست بداند مستقیماً با سرور اصلی در ارتباط است یا درخواست از واسطه‌هایی مثل درگاه API، پراکسی یا سیستم Cache عبور می‌کند. این لایه‌ها می‌توانند بدون تغییر نحوه استفاده کلاینت از API به معماری اضافه شوند.

در کنار این موارد، REST یک محدودیت اختیاری به نام Code on Demand (اجرای کد در سمت کاربر) هم دارد که به سرور اجازه می‌دهد کد قابل اجرا برای کلاینت ارسال کند. برخلاف اصول قبلی، رعایت این مورد برای RESTful بودن API الزامی نیست.

تفاوت Resource و Endpoint

Resource و Endpoint؛ نحوه تعریف و دسترسی به منابع در REST

در REST، اول باید مشخص کنیم API قرار است با چه چیزهایی کار کند. این «چیزها» همان Resource (منبع) هستند؛ مثلاً کاربر، سفارش، محصول یا در مثال این مقاله، «دوره آموزشی».

هر Resource از طریق یک Endpoint (آدرس مشخص برای دسترسی به منبع) در API قابل دسترسی است. مثلاً:

/courses

این آدرس به مجموعه دوره‌ها اشاره می‌کند. اگر بخواهیم به یک دوره مشخص برسیم، شناسه آن را هم به آدرس اضافه می‌کنیم:

/courses/25

یعنی «دوره شماره ۲۵».

نکته مهم اینجاست که Endpoint فقط مشخص می‌کند با کدام منبع سروکار داریم، نه اینکه قرار است چه کاری روی آن انجام شود. نوع عملیات را متد HTTP مشخص می‌کند. برای مثال:

GET /courses/25

DELETE /courses/25

هر دو درخواست به همان دوره شماره ۲۵ مربوط‌اند، اما یکی اطلاعاتش را دریافت می‌کند و دیگری آن را حذف می‌کند.

چرا نام عملیات را داخل Endpoint نمی‌آوریم؟

در طراحی RESTful معمولاً خود منبع در آدرس می‌آید و عملیات به متد HTTP سپرده می‌شود. بنابراین به‌جای:

/getCourses

/createCourse

/deleteCourse/25

ساختار ساده‌تر و قابل‌پیش‌بینی‌تری داریم:

/courses

/courses/25

و بعد GET، POST، PUT، PATCH یا DELETE مشخص می‌کند چه کاری باید انجام شود.

این تفکیک یک مزیت مهم دارد: آدرس می‌گوید «روی چه چیزی؟» و متد می‌گوید «چه کاری؟» همین الگو باعث می‌شود ساختار API منظم‌تر باشد و توسعه‌دهنده برای فهم هر عملیات مجبور نباشد با مجموعه‌ای از آدرس‌های متفاوت روبه‌رو شود.

اگر در ابتدای مسیر توسعه نرم‌افزار هستید و می‌خواهید قبل از این جزئیات، تصویر کامل‌تری از فرایند ساخت نرم‌افزار داشته باشید، مقاله برنامه‌نویسی چیست می‌تواند به شما کمک کند.

متدهای HTTP

متدهای HTTP و کاربرد آن‌ها در RESTful API

تا اینجا مشخص شد که Endpoint می‌گوید با کدام منبع کار داریم. متد HTTP مشخص می‌کند چه کاری قرار است روی آن منبع انجام شود. برای مثال، /courses/25 همیشه به دوره شماره ۲۵ اشاره دارد؛ اما با تغییر متد، عملیاتی که روی این دوره انجام می‌شود هم تغییر می‌کند.

عملیاتEndpointمتدBody  کد وضعیت رایج
دریافت فهرست دوره‌ها/coursesGETندارد۲۰۰ OK
دریافت یک دوره/courses/25GETندارد۲۰۰ OK
ایجاد دوره جدید/coursesPOSTاطلاعات دوره۲۰۱ Created
جایگزینی کامل اطلاعات دوره/courses/25PUTاطلاعات کامل دوره۲۰۰ OK یا ۲۰۴ No Content
تغییر بخشی از اطلاعات دوره/courses/25PATCHفقط اطلاعاتی که تغییر می‌کنند۲۰۰ OK یا ۲۰۴ No Content
حذف دوره/courses/25DELETEمعمولاً ندارد۲۰۴ No Content

Body (بدنه درخواست) جایی است که داده‌های مورد نیاز همراه درخواست فرستاده می‌شوند. مثلاً برای ساخت یک دوره جدید، عنوان، نام مدرس و قیمت می‌توانند در Body قرار بگیرند.

GET، POST و DELETE چه تفاوتی دارند؟

GET زمانی استفاده می‌شود که فقط می‌خواهیم اطلاعاتی را دریافت کنیم. برای مثال:

GET /courses/25

اطلاعات دوره شماره ۲۵ را می‌خواهد و نباید تغییری در خود دوره ایجاد کند.

برای ساخت یک دوره جدید می‌توانیم از POST استفاده کنیم. در این حالت درخواست به /courses ارسال می‌شود و مشخصات دوره جدید در Body قرار می‌گیرد.

DELETE هم برای حذف یک منبع مشخص است:

DELETE /courses/25

در این مثال، منبع مورد نظر همان دوره شماره ۲۵ است و عملیات حذف را متد DELETE مشخص می‌کند.

تفاوت PUT و PATCH چیست؟

هر دو برای ویرایش اطلاعات استفاده می‌شوند، اما میزان تغییری که بیان می‌کنند یکسان نیست.

فرض کنید اطلاعات دوره شماره ۲۵ شامل عنوان، مدرس، توضیحات و قیمت است. اگر بخواهیم نمای کامل اطلاعات دوره را با نسخه جدید جایگزین کنیم، PUT انتخاب رایجی است و معمولاً اطلاعات کامل Resource در درخواست فرستاده می‌شود.

اما اگر فقط قیمت دوره تغییر کرده باشد، PATCH دقیق‌تر نشان می‌دهد چه اتفاقی قرار است بیفتد. در این حالت می‌توان فقط همان فیلد را ارسال کرد:

{

  “price”: 850000

}

پس به زبان ساده، PUT معمولاً برای جایگزینی کامل و PATCH برای تغییر بخشی از اطلاعات یک Resource استفاده می‌شود.

تکرارپذیری در متدهای HTTP به چه معناست؟

Idempotency (تکرارپذیری بدون تغییر نتیجه نهایی) در نگاه اول اصطلاح پیچیده‌ای است، اما مفهوم ساده‌ای دارد: اگر یک درخواست یکسان را چند بار ارسال کنیم، وضعیت نهایی منبع باید مانند زمانی باشد که آن درخواست فقط یک بار انجام شده است.

مثلاً فرض کنید با PUT قیمت دوره شماره ۲۵ را روی ۸۵۰ هزار تومان قرار می‌دهیم. اگر همان درخواست را دوباره ارسال کنیم، قیمت همچنان ۸۵۰ هزار تومان است؛ Resource جدیدی ساخته نمی‌شود و نتیجه نهایی تغییر نمی‌کند.

DELETE هم از همین منطق پیروی می‌کند. چند بار درخواست حذف دوره شماره ۲۵ همچنان یک هدف دارد: این دوره دیگر وجود نداشته باشد. البته پاسخ سرور در درخواست‌های بعدی می‌تواند متفاوت باشد؛ مثلاً بعد از حذف اولیه، سرور اعلام کند که چنین منبعی پیدا نشده است. Idempotency درباره وضعیت نهایی منبع است، نه یکسان‌بودن پاسخ‌ها.

در مقابل، POST معمولاً Idempotent نیست. اگر درخواست ساخت یک دوره را چند بار ارسال کنید، ممکن است هر بار یک دوره جدید ساخته شود.

نمونه Request و Response

نمونه Request و Response در REST API

فرض کنید قرار است یک دوره جدید در سیستم ساخته شود. کلاینت یک Request (درخواست) با متد POST به Endpoint دوره‌ها می‌فرستد.

مثال درخواست:

Method: POST
Endpoint: /courses
Content-Type: application/json

اطلاعات دوره هم در Body (بدنه درخواست) قرار می‌گیرد:

title: آموزش Git
instructor: Ali Ahmadi
price: 850000

در همین درخواست چند اطلاعات مهم وجود دارد. POST مشخص می‌کند قرار است منبع جدیدی ایجاد شود، /courses نشان می‌دهد با منبع دوره‌ها سروکار داریم و Content-Type به سرور می‌گوید داده‌های ارسالی با چه فرمتی نوشته شده‌اند. 

در این مثال از JSON استفاده شده است؛ قالبی متنی و ساختاریافته برای نمایش و انتقال داده که در APIها کاربرد زیادی دارد. اگر دوره با موفقیت ساخته شود، Response (پاسخ) سرور می‌تواند شامل این اطلاعات باشد:

Status Code: 201 Created
Content-Type: application/json

id: 25
title: آموزش Git
instructor: Ali Ahmadi
price: 850000

کد ۲۰۱ Created یعنی درخواست با موفقیت انجام شده و یک منبع جدید ساخته شده است. در بدنه پاسخ هم اطلاعات دوره به همراه شناسه‌ای که سرور برای آن ایجاد کرده، برگردانده می‌شود.

اگر داده‌های یک درخواست ناقص باشند، چه اتفاقی می‌افتد؟

فرض کنید عنوان دوره اجباری است، اما در Body فقط این اطلاعات ارسال شده‌اند:

instructor: Ali Ahmadi
price: 850000

سرور باید علاوه بر اعلام ناموفق‌بودن درخواست، دلیل خطا را هم مشخص کند. برای مثال:

Status Code: 400 Bad Request
Error: title is required

در این پاسخ، ۴۰۰ Bad Request نشان می‌دهد مشکلی در درخواست وجود دارد و پیام خطا مشخص می‌کند عنوان دوره ارسال نشده است.

برای بررسی یک درخواست REST می‌توان چهار سؤال ساده پرسید: درخواست به کدام Endpoint رفته؟ با چه متدی؟ چه داده‌ای همراه آن بوده؟ سرور با چه Status Code و اطلاعاتی پاسخ داده است؟ پاسخ همین چهار سؤال، ساختار Request و Response را تا حد زیادی روشن می‌کند.

مدیریت پاسخ‌ها و خطاهای REST API با Status Code

وقتی سرور به یک درخواست پاسخ می‌دهد، باید نتیجه آن هم برای کلاینت مشخص باشد. Status Code (کد وضعیت) همین کار را انجام می‌دهد و نشان می‌دهد درخواست موفق بوده، مشکلی در اطلاعات ارسالی وجود داشته یا خطایی در سمت سرور رخ داده است.

در یک REST API معمولاً با این کدها بیشتر سروکار داریم:

کد وضعیتمعنینمونه در API دوره‌ها
۲۰۰ OKدرخواست با موفقیت انجام شدهاطلاعات دوره شماره ۲۵ دریافت شده است
۲۰۱ Createdمنبع جدید ساخته شده استیک دوره جدید ایجاد شده است
۲۰۴ No Contentعملیات موفق بوده و نیازی به Body پاسخ نیستدوره حذف شده است
۴۰۰ Bad Requestاطلاعات یا ساختار درخواست معتبر نیستعنوان الزامی دوره ارسال نشده است
۴۰۱ Unauthorizedدرخواست نیاز به احراز هویت داردکاربر بدون احراز هویت درخواست ارسال کرده است
۴۰۳ Forbiddenکاربر احراز هویت شده اما اجازه این کار را نداردکاربر اجازه حذف دوره را ندارد
۴۰۴ Not Foundمنبع مورد نظر پیدا نشده استدوره‌ای با شناسه درخواستی وجود ندارد
۵۰۰ Internal Server Errorهنگام پردازش درخواست، خطایی در سرور رخ داده استسرور با یک خطای پیش‌بینی‌نشده مواجه شده است

تفاوت ۴۰۱ و ۴۰۳ مهم است: در حالت اول، مسئله احراز هویت است؛ در حالت دوم، هویت کاربر مشخص شده اما مجوز انجام آن عملیات را ندارد.

چرا نباید برای همه پاسخ‌ها ۲۰۰ برگردانیم؟

فرض کنید کلاینت اطلاعات /courses/999 را درخواست می‌کند، اما دوره‌ای با این شناسه وجود ندارد. اگر سرور ۲۰۰ OK برگرداند و فقط داخل Body بنویسد «دوره پیدا نشد»، کد وضعیت دیگر نتیجه واقعی درخواست را نشان نمی‌دهد.

پاسخ مناسب‌تر ۴۰۴ Not Found است. کلاینت از روی همین کد متوجه می‌شود منبع موردنظر وجود ندارد و Body می‌تواند جزئیات بیشتری درباره خطا ارائه کند.

همین موضوع در تشخیص خطاها هم اهمیت دارد. ۴۰۰ می‌گوید ایرادی در درخواست وجود دارد؛ ۴۰۴ از پیدا نشدن منبع خبر می‌دهد و ۵۰۰ نشان می‌دهد مشکل هنگام پردازش درخواست در سمت سرور رخ داده است. این تفاوت به کلاینت کمک می‌کند برای هر وضعیت واکنش مناسبی داشته باشد.

پیام خطا باید چه چیزی را مشخص کند؟

Status Code نوع خطا را مشخص می‌کند، اما همیشه توضیح نمی‌دهد دقیقاً چه چیزی اشتباه است. برای همین، پاسخ خطا بهتر است یک پیام مشخص و قابل‌استفاده هم داشته باشد.

مثلاً اگر هنگام ایجاد دوره، عنوان ارسال نشده باشد:

Status Code: 400 Bad Request
Error: .عنوان دوره الزامی است

در این مثال، ۴۰۰ وضعیت درخواست را مشخص می‌کند و پیام خطا می‌گوید چه چیزی باید اصلاح شود. بنابراین یک پاسخ مناسب فقط اعلام نمی‌کند که «خطایی رخ داده»؛ اطلاعات کافی برای تشخیص مشکل را هم در اختیار کلاینت می‌گذارد.

طراحی استاندارد RESTful API

یک RESTful API خوب چه ویژگی‌هایی دارد؟

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

  • نام‌گذاری را ساده و یکدست نگه دارید.

Endpointها را براساس Resourceها نام‌گذاری کنید و انجام عملیات را به متدهای HTTP بسپارید. یک الگوی نام‌گذاری مشخص را هم در سراسر API حفظ کنید.

  • ساختار Request و Response را قابل‌پیش‌بینی طراحی کنید.

شیوه ارسال داده، نام فیلدها، ساختار پاسخ‌ها و فرمت خطاها بهتر است در Endpointهای مختلف از الگوی مشترکی پیروی کنند. این هماهنگی استفاده و نگهداری API را ساده‌تر می‌کند.

  • از Status Code درست استفاده کنید.

کد وضعیت باید نتیجه واقعی درخواست را نشان دهد. کلاینت باید بتواند از روی Status Code تشخیص دهد عملیات موفق بوده، درخواست مشکلی داشته یا خطایی در سرور رخ داده است.

  • فقط اطلاعات مورد نیاز را منتقل کنید.

Request و Response نباید بی‌دلیل با داده‌های اضافی سنگین شوند. اطلاعات حساس هم نباید صرفاً چون در سمت سرور در دسترس هستند، در پاسخ API قرار بگیرند.

  • تغییرات API را مدیریت کنید.

تغییر ساختار پاسخ‌ها، حذف فیلدها یا تغییر رفتار Endpointها ممکن است کلاینت‌های فعلی را دچار مشکل کند. تغییرات ناسازگار باید کنترل‌شده انجام شوند و در صورت نیاز از Versioning (نسخه‌بندی API) استفاده شود.

RESTful API بخشی از مهارت‌های عملی توسعه نرم‌افزار است و در مسیر Frontend و Backend بارها با آن سروکار خواهید داشت. برای ادامه این مسیر می‌توانید موضوعات و دوره‌های مرتبط را در بخش آموزش برنامه‌نویسی دنبال کنید.

جمع‌بندی

RESTful API را می‌توان با چند سؤال ساده خواند: منبع چیست، آدرسش کجاست، چه عملیاتی روی آن انجام می‌شود و سرور چه پاسخی برمی‌گرداند؟

Resource و Endpoint مشخص می‌کنند با چه چیزی سروکار داریم، متدهای HTTP نوع عملیات را تعیین می‌کنند و Status Code نتیجه درخواست را نشان می‌دهد. اصول REST هم کمک می‌کنند این اجزا به‌جای مجموعه‌ای از آدرس‌ها و قواعد پراکنده، از یک منطق مشخص پیروی کنند.

پس وقتی با یک REST API جدید روبه‌رو می‌شوید، به‌جای حفظ‌کردن Endpointها، اول الگوی طراحی آن را پیدا کنید. اگر منابع، متدها و پاسخ‌ها با منطق ثابتی طراحی شده باشند، فهمیدن و کارکردن با API هم بسیار ساده‌تر می‌شود.

امتیاز دهید
ترمه افضلی

ترمه افضلی

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

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *