اولین بار که در یک پروژه فریلنسری مجبور شدم سایتی را با یک سیستم خارجی همگام کنم، با مفهوم REST API (Representational State Transfer Application Programming Interface) رودررو شدم. چند روز اول را صرف خواندن مستنداتی کردم که همه از GET و POST حرف می‌زدند اما هیچ‌کدام نمی‌گفتند چرا این ساختار، این‌طور طراحی شده. تجربه‌ام می‌گوید اگر پیش از هر کد، مدل ذهنی درست ساخته شود، یادگیری REST چند برابر سریع‌تر می‌شود. این نوشته همان مسیری است که در پروژه‌های واقعی برای شروع با REST API طی کرده‌ام.

REST API چیست و چه تفاوتی با API ساده دارد؟

REST یک سبک معماری (architectural style) برای طراحی سرویس‌های وب است که اولین بار در پایان‌نامه‌ای دانشگاهی توصیف شد و بعد به استاندارد غیررسمی صنعت تبدیل شد. تفاوتش با یک API معمولی در این است که REST اصول مشخصی دارد: بی‌حالت بودن (stateless)، استفاده از متدهای استاندارد HTTP (HyperText Transfer Protocol)، و مدل‌سازی منابع به‌صورت URL (Uniform Resource Locator). اگر با مفهوم کلی API وردپرس آشنا نیستید، افزونه وردپرس چیست نقطه شروع خوبی است؛ چون اکثر افزونه‌ها امروز از REST API برای تبادل داده استفاده می‌کنند.

REST، یک سبک است نه یک استاندارد اجباری؛ اما در عمل، وقتی همه از یک سبک مشترک استفاده می‌کنند، کل اینترنت سریع‌تر و قابل‌پیش‌بینی‌تر کار می‌کند.

مدل ذهنی: چطور REST را بفهمیم؟

یک مدل ذهنی ساده که در پروژه‌های واقعی زیاد استفاده می‌کنم: REST API مثل یک کتابخانه عمومی است. هر کتاب در یک قفسه مشخص (URL)، با یک برچسب مشخص (resource) قرار دارد. شما می‌توانید یک کتاب را ببینید (GET)، کتاب جدید اضافه کنید (POST)، کتاب موجود را به‌روز کنید (PUT) یا آن را حذف کنید (DELETE). هیچ‌کس از شما نمی‌پرسد برای بار دوم چه کار می‌کنید؛ هر درخواست، مستقل از درخواست قبلی است. همین بی‌حالت بودن، دلیل مقیاس‌پذیری REST است.

اصول پایه REST:

  • منابع، نه افعال: در URL از اسم استفاده کنید (/users، /orders)، نه از فعل (getUsers).
  • بی‌حالت بودن: سرور بین درخواست‌ها، اطلاعات کاربر را در حافظه نگه نمی‌دارد.
  • متدهای استاندارد: از همان GET، POST، PUT، PATCH و DELETE که HTTP تعریف کرده استفاده کنید.
  • نمایش قابل‌کش: پاسخ‌ها را می‌توان کش کرد؛ همین اصل، نقش بزرگی در سرعت بازی می‌کند.

متدهای HTTP در REST

پنج متد HTTP که در REST بیشترین کاربرد را دارند، در جدول زیر خلاصه شده‌اند:

متدکاربردکش‌پذیر
GETخواندن دادهبله
POSTساخت منبع جدیدخیر
PUTجایگزینی کامل منبعخیر
PATCHبه‌روزرسانی جزئی منبعخیر
DELETEحذف منبعخیر

نمونه یک API ساده با مدل‌سازی منابع:

GET    /api/users         # فهرست کاربران
GET    /api/users/42      # کاربر شماره ۴۲
POST   /api/users         # ساخت کاربر جدید
PUT    /api/users/42      # جایگزینی کامل
PATCH  /api/users/42      # به‌روزرسانی جزئی
DELETE /api/users/42      # حذف کاربر

تفاوت PUT و PATCH در تجربه من یکی از پرتکرارترین سؤالات توسعه‌دهندگان تازه‌کار است. قاعده ساده: PUT یعنی «این محتوای جدید را جایگزین کن» و باید همه فیلدها را بفرستد. PATCH یعنی «فقط این فیلد را عوض کن». اگر برای صرفه‌جویی در پهنای باند PATCH را با PUT جابه‌جا کنید، کاربران دیگر نمی‌توانند داده کامل بفرستند و در آینده باگ‌های عجیبی می‌سازد.

کدهای وضعیت HTTP

کدهای وضعیت (status codes) از مهم‌ترین اجزای REST API هستند، چون بدون آن‌ها کاربر API نمی‌فهمد درخواست موفق بوده یا نه. کدهای کلیدی که در طراحی هر API باید استاندارد بمانند:

  • 2xx موفق: 200 OK، 201 Created، 204 No Content
  • 3xx ریدایرکت: 301 Moved Permanently، 304 Not Modified
  • 4xx خطای کاربر: 400 Bad Request، 401 Unauthorized، 403 Forbidden، 404 Not Found، 422 Unprocessable Entity
  • 5xx خطای سرور: 500 Internal Server Error، 503 Service Unavailable

اشتباه رایجی که در پروژه‌های واقعی دیده‌ام: بعضی توسعه‌دهندگان، همه چیز را با 200 برمی‌گردانند و خطا را داخل بدنه JSON می‌گذارند. این کار کلاینت‌های REST را به‌هم می‌ریزد، چون رفتار استاندارد کلاینت‌ها بر اساس کد وضعیت است، نه بدنه پاسخ.

JSON و ساختار داده

JSON (JavaScript Object Notation) امروز زبان پیش‌فرض تبادل داده در REST است، چون سبک، خوانا و مستقل از زبان برنامه‌نویسی است. الگوی من برای پاسخ‌های JSON در پروژه‌ها: یک ساختار ثابت در همه پاسخ‌ها، با فیلدهای data و meta و errors:

{
  "data": {
    "id": 42,
    "name": "علی",
    "email": "ali@example.com"
  },
  "meta": {
    "created_at": "2026-01-15T10:00:00Z"
  }
}

در خطا:

{
  "errors": [
    {
      "code": "validation_error",
      "field": "email",
      "message": "ایمیل معتبر نیست"
    }
  ]
}

یکسان بودن ساختار پاسخ‌ها، بار کلاینت را چند برابر کم می‌کند. اگر بعداً افزونه‌ای روی وردپرس نصب کنید که با REST API کار می‌کند، همین استاندارد به کار شما هم می‌آید.

احراز هویت در REST API

چون REST بی‌حالت است، احراز هویت هم باید در هر درخواست اتفاق بیفتد. سه روش رایج:

  1. Basic Authentication: ساده، اما بدون HTTPS (HyperText Transfer Protocol Secure) بسیار ناامن. فقط برای محیط تست یا APIهای داخلی.
  2. API Key: یک کلید ثابت در هدر یا پارامتر. مناسب برای سرویس‌های داخلی یا یکپارچه‌سازی محدود.
  3. JWT (JSON Web Token): توکن امضاشده که اطلاعات کاربر را در خودش دارد. رایج‌ترین روش برای APIهای عمومی امروز.

جدا از روش احراز هویت، سه قاعده همیشگی در پروژه‌ها: همیشه از HTTPS استفاده کنید، توکن‌ها را در URL نگذارید (چون در لاگ‌ها می‌مانند)، و زمان انقضای توکن‌ها را کوتاه و امکان تمدید را فراهم کنید. مقایسه جزئیات امنیتی API در بهترین افزونه‌های امنیتی وردپرس آمده است.

ساخت یک REST API ساده با PHP

برای درک عملی، یک endpoint ساده که لیست کاربران را برمی‌گرداند را در PHP خالص می‌نویسیم. این مثال، پایه‌ای است که در پروژه‌های واقعی برای ساخت endpointهای سبک استفاده می‌کنم:

<?php
header('Content-Type: application/json; charset=utf-8');

$method = $_SERVER['REQUEST_METHOD'];
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);

if ($method === 'GET' && $path === '/api/users') {
    $users = [
        ['id' => 1, 'name' => 'علی'],
        ['id' => 2, 'name' => 'سارا'],
    ];
    http_response_code(200);
    echo json_encode(['data' => $users], JSON_UNESCAPED_UNICODE);
    exit;
}

http_response_code(404);
echo json_encode(['errors' => [['message' => 'Not found']]]);

سه نکته مهم در این کد: اول، هدر Content-Type با charset=utf-8 تنظیم شده تا متن فارسی درست نمایش داده شود. دوم، از JSON_UNESCAPED_UNICODE استفاده شده تا کاراکترهای فارسی به بایت‌های یونیکد تبدیل نشوند. سوم، در همه مسیرها exit صدا زده شده تا پاسخ‌های اضافه ارسال نشود. این سه، شایع‌ترین اشتباهات کدهای REST در PHP هستند.

در پروژه‌های واقعی، همین ساختار با یک روتر (router) و یک لایه کنترلر سازمان می‌یابد. اگر بخواهید مسیر یکپارچه‌سازی با وردپرس را ببینید، افزونه‌ای بسازید که یک endpoint به REST API وردپرس اضافه کند؛ برای آشنایی با مفاهیم پایه افزونه، افزونه وردپرس چیست را ببینید.

REST API خوب، مثل یک قرارداد شفاف است؛ هر کلاینتی که این قرارداد را بفهمد، می‌تواند بدون مستندات اضافی با شما کار کند.

تست REST API با curl و Postman

هر endpoint که می‌سازید، بلافاصله تستش کنید. دو ابزار اصلی:

با curl در ترمینال:

curl -X GET https://example.com/api/users -H "Accept: application/json"

curl -X POST https://example.com/api/users 
  -H "Content-Type: application/json" 
  -H "Authorization: Bearer TOKEN_HERE" 
  -d '{"name":"مریم","email":"maryam@example.com"}'

و با Postman، که امکان ذخیره و اشتراک‌گذاری مجموعه درخواست‌ها را دارد. توصیه من: برای هر endpoint، سه تست استاندارد بنویسید: موفق (happy path)، خطای اعتبارسنجی، و خطای دسترسی. این سه، بیشتر باگ‌های پنهان را قبل از انتشار لو می‌دهند. مقایسه ابزارهای تست API در تست REST API با Postman آمده است.

اشتباهات رایج در طراحی REST API

ده سال کار با API، پنج اشتباه را بیشتر از بقیه دیده‌ام:

  1. فعل در URL: /getUsers یا /createUser، به‌جای /users و POST /users.
  2. کد وضعیت ۲۰۰ برای همه چیز: باعث می‌شود کلاینت نتواند موفق یا ناموفق بودن را بفهمد.
  3. نبود نسخه‌بندی (versioning): فردا که ساختار تغییر کند، کلاینت‌های قدیمی می‌شکنند. حداقل از روز اول /api/v1/ را داشته باشید.
  4. بازگرداندن همه چیز در یک درخواست: پاسخ‌های حجیم، سرعت را پایین می‌آورند. امکان pagination و فیلتر را از روز اول پیش‌بینی کنید.
  5. عدم مستندسازی: API بدون مستندات، عملاً استفاده‌ناپذیر است. OpenAPI Specification (که قبلاً Swagger نامیده می‌شد) استانداردی است که در پروژه‌های جدی استفاده می‌کنم.

ملاحظات محیط واقعی

قبل از اینکه API شما به دست کاربران واقعی برسد، چند نکته که در تجربه من از قلم می‌افتند:

  • محدودسازی نرخ (rate limiting): هر کلاینت، سقف تعداد درخواست در دقیقه داشته باشد. بدون این، یک کلاینت معیوب یا مهاجم می‌تواند سرویس را از کار بیندازد. مفهوم حمله DDoS در حمله DDoS چیست آمده است.
  • لاگ‌گیری و مانیتورینگ: هر درخواست، با متد، مسیر، کد وضعیت و زمان پاسخ ثبت شود. اگر روزی سیستم کند شد، همین لاگ‌ها نجات‌دهنده‌اند. تحلیل سرعت را در بهترین ابزارهای تست سرعت سایت ببینید.
  • CORS (Cross-Origin Resource Sharing): اگر API روی دامنه‌ای جدا از فرانت اجرا می‌شود، تنظیمات CORS را با دقت انجام دهید. اشتباه رایج، باز گذاشتن * در production است که امنیت را تهدید می‌کند.
  • مستندسازی خودکار: OpenAPI را از همان ابتدا بخشی از پروژه کنید، نه کار جانبی. خروجی خودکار آن، به‌روز نگه داشتن مستندات را ساده می‌کند.
  • آزمون امنیتی: حداقل پیش از انتشار، با ابزارهای اسکن بدافزار و بررسی آسیب‌پذیری، مسیرهای اصلی را از نظر XSS و SQL Injection تست کنید. مفاهیم در حملات XSS و راه‌های مقابله آمده است.
API در آزمایشگاه، فقط یک قرارداد است؛ API در محیط واقعی، قرارداد به‌علاوه امنیت، مانیتورینگ و مستندات.

پرسش‌های کوتاه

REST و HTTP چه تفاوتی دارند؟ HTTP پروتکلی است که مرورگر و سرور با آن حرف می‌زنند؛ REST یک سبک معماری روی همان پروتکل. یعنی REST بدون HTTP معنا ندارد.

آیا REST از GraphQL بهتر است؟ بستگی به سناریو دارد. REST برای بیشتر APIها کافی و ساده‌تر است؛ GraphQL برای کلاینت‌هایی که به فیلدهای مختلف از منابع متنوع نیاز دارند، کارآمدتر است.

آیا باید از ابتدا نسخه‌بندی کنم؟ بله. حتی اگر امروز فقط یک کلاینت دارید، فردا روزی ممکن است چند کلاینت داشته باشید. پیشوند /api/v1/ کم‌هزینه است و آینده را نجات می‌دهد.

JSON یا XML؟ برای اکثر APIهای امروز، JSON. XML در برخی از سرویس‌های سازمانی و در سیستم‌های قدیمی‌تر رایج است؛ اگر مجبور نیستید، JSON انتخاب درست است.

سخن آخر

REST API، اگر پیش از نوشتن کد، مدل ذهنی درستی از منابع، متدها و کدهای وضعیت داشته باشید، ساده‌تر از آنچه به‌نظر می‌رسد می‌شود. تجربه من می‌گوید بیشتر پروژه‌هایی که در آن‌ها REST API دچار دردسر شد، مشکلشان نه فنی، که مفهومی بود: resource را با action قاطی کردند، کدهای وضعیت را جدی نگرفتند و نسخه‌بندی را به بعد موکول کردند. اگر امروز فقط یک کار بکنید، یک endpoint ساده بسازید، سه تست استاندارد برای آن بنویسید و مستندسازی OpenAPI را از همان روز اول شروع کنید. باقی مسیر، ساختن روی همان پایه است. اگر در پروژه‌ای به نکته‌ای از طراحی REST برخوردید که در منابع عمومی کمتر گفته شده، در دیدگاه‌ها بنویسید؛ همان تجربه برای نفر بعدی ارزشمندتر از هر مستند رسمی است. 🔌