RAJESTARY DIGITAL TECH • SECURITY • EDUCATION
دانش • فناوری • امنیت

دنیای تکنولوژی
از یادگیری شروع می‌شود

آموزش‌های کاربردی، برنامه‌نویسی، امنیت و فناوری برای ساختن، یادگرفتن و بهتر زندگی کردن با تکنولوژی.

LEARN BUILD SECURE CREATE

API Versioning و مدیریت چرخه حیات

API Versioning و مدیریت چرخه حیات

📖 درس هشتم: API Versioning و مدیریت چرخه حیات

👋

سلام مهمان عزیز!

برای دسترسی به تمام محتوا و امکانات، وارد شوید.

🎯 هدف این درس: آشنایی با استراتژی‌های نسخه‌بندی API، مدیریت Deprecation، حفظ Backward Compatibility و نحوه مهاجرت کاربران از نسخه‌های قدیمی به جدید.

مهمان عزیز! 👋
API شما در حال رشد است و روز به روز کاربران بیشتری از آن استفاده می‌کنند. اما سوال اینجاست: وقتی می‌خواهید تغییری در API ایجاد کنید که با نسخه قبلی سازگار نیست، چه باید کرد؟

اگر تغییرات را اعمال کنید، کاربران قدیمی شما ممکن است دچار مشکل شوند. اگر تغییرات را اعمال نکنید، API شما از رقبا عقب می‌ماند. راه حل این است: نسخه‌بندی (Versioning).

💡 چرا نسخه‌بندی API مهم است؟

  • ✅ امکان تغییر و بهبود API بدون شکستن کد کاربران.
  • ✅ ارائه قابلیت‌های جدید به صورت تدریجی.
  • ✅ مدیریت چرخه حیات API و حذف تدریجی نسخه‌های قدیمی.
  • ✅ ایجاد اعتماد در کاربران که API شما پایدار است.
  • ✅ امکان تست نسخه‌های جدید با کاربران محدود (Beta Testing).

🗺️ استراتژی‌های نسخه‌بندی API

سه استراتژی اصلی برای نسخه‌بندی API وجود دارد:

استراتژی مثال مزایا معایب
URI Path /v1/users ساده، واضح، قابل کش تغییر URL، نیاز به هدایت
Query Parameter /users?version=1 ساده، بدون تغییر URL کمتر واضح، مشکلات کش
Header API-Version: 1 URL تمیز، RESTful کمتر قابل مشاهده، تست سخت‌تر

⚠️ توصیه مهم:

استراتژی URI Path (مانند /v1/users) محبوب‌ترین و توصیه‌شده‌ترین روش است، زیرا:

  • ✅ واضح و قابل فهم است.
  • ✅ با CDN و پروکسی‌ها به خوبی کار می‌کند.
  • ✅ به راحتی در مستندات قابل نمایش است.
  • ✅ امکان هدایت و ریدایرکت ساده دارد.

🔄 پیاده‌سازی URI Versioning

بیایید نسخه‌بندی URI را در مسیریاب پیاده‌سازی کنیم:



🔄
Router.php (با نسخه‌بندی)

PHP
8.2




<?php

class Router
{
    private $routes = [];
    private $version = 'v1';
    private $supportedVersions = ['v1', 'v2'];
    private $deprecatedVersions = ['v1'];
    private $defaultVersion = 'v2';

    // اضافه کردن مسیر با نسخه مشخص
    public function add($method, $path, $controller, $action, $version = 'v1')
    {
        $this->routes[] = [
            'method' => $method,
            'path' => '/' . $version . $path,
            'controller' => $controller,
            'action' => $action,
            'version' => $version
        ];
    }

    // پردازش درخواست با تشخیص نسخه
    public function dispatch($request)
    {
        $method = $request->getMethod();
        $uri = $request->getUri();

        // تشخیص نسخه از URI
        $version = $this->extractVersion($uri);

        // بررسی پشتیبانی از نسخه
        if (!in_array($version, $this->supportedVersions)) {
            return new Response(400, [
                'error' => 'Unsupported API version',
                'supported_versions' => $this->supportedVersions
            ]);
        }

        // هشدار برای نسخه‌های منسوخ شده
        if (in_array($version, $this->deprecatedVersions)) {
            header('Warning: 299 - "This API version is deprecated. Please upgrade to v2"');
        }

        // حذف نسخه از URI برای تطبیق
        $uriWithoutVersion = preg_replace('#^/' . $version . '#i', '', $uri);

        // جستجوی مسیر
        foreach ($this->routes as $route) {
            $pattern = preg_replace('/\{([a-zA-Z]+)\}/', '([^/]+)', $route['path']);
            $pattern = '#^' . $pattern . '$#';

            // تطبیق متد و مسیر
            if ($route['method'] === $method && 
                $route['version'] === $version &&
                preg_match($pattern, $uriWithoutVersion, $matches)) {
                
                array_shift($matches);
                $params = $matches;

                $controllerName = $route['controller'];
                $actionName = $route['action'];

                // انتخاب کنترلر بر اساس نسخه
                $controllerClass = $controllerName . $version;
                
                if (!class_exists($controllerClass)) {
                    $controllerClass = $controllerName;
                }

                $controller = new $controllerClass();
                return $controller->$actionName($request, $params);
            }
        }

        return new Response(404, ['error' => 'Endpoint not found']);
    }

    // استخراج نسخه از URI
    private function extractVersion($uri)
    {
        if (preg_match('#^/(v[0-9]+)/#i', $uri, $matches)) {
            return strtolower($matches[1]);
        }
        
        // اگر نسخه مشخص نشده، از نسخه پیش‌فرض استفاده کن
        return $this->defaultVersion;
    }

    // تنظیم نسخه‌های پشتیبانی شده
    public function setSupportedVersions($versions)
    {
        $this->supportedVersions = $versions;
    }

    // تنظیم نسخه‌های منسوخ شده
    public function setDeprecatedVersions($versions)
    {
        $this->deprecatedVersions = $versions;
    }
}

🧪 نسخه‌های مختلف کنترلر

برای هر نسخه، یک کنترلر مجزا ایجاد می‌کنیم تا تغییرات را به صورت مستقل مدیریت کنیم:



🧪
UserControllerv1.php

PHP
8.2




<?php

// ========== نسخه ۱ (قدیمی) ==========
class UserControllerv1
{
    private $userModel;

    public function __construct()
    {
        require_once __DIR__ . '/../Models/User.php';
        $this->userModel = new User();
    }

    // GET /v1/users - دریافت کاربران (نسخه ۱: فقط نام و ایمیل)
    public function index($request)
    {
        $users = $this->userModel->getAll();
        
        // نسخه ۱: فقط فیلدهای پایه
        $result = array_map(function($user) {
            return [
                'id' => $user['id'],
                'name' => $user['name'],
                'email' => $user['email']
            ];
        }, $users);

        return Response::success($result);
    }

    // GET /v1/users/{id} - دریافت یک کاربر
    public function show($request, $params)
    {
        $user = $this->userModel->find($params[0]);
        
        if (!$user) {
            return Response::notFound();
        }

        // نسخه ۱: فقط فیلدهای پایه
        return Response::success([
            'id' => $user['id'],
            'name' => $user['name'],
            'email' => $user['email']
        ]);
    }

    // POST /v1/users - ایجاد کاربر
    public function store($request)
    {
        $data = $request->getBody();
        
        // اعتبارسنجی ساده (نسخه ۱)
        if (empty($data['name']) || empty($data['email'])) {
            return Response::error('Name and email are required', 422);
        }

        $user = $this->userModel->create($data);
        
        return Response::created($user);
    }
}


🧪
UserControllerv2.php

PHP
8.2




<?php

// ========== نسخه ۲ (جدید و بهبود یافته) ==========
class UserControllerv2
{
    private $userModel;

    public function __construct()
    {
        require_once __DIR__ . '/../Models/User.php';
        $this->userModel = new User();
    }

    // GET /v2/users - دریافت کاربران با اطلاعات کامل
    public function index($request)
    {
        $page = $_GET['page'] ?? 1;
        $limit = $_GET['limit'] ?? 10;

        $users = $this->userModel->getAll($page, $limit);
        $total = $this->userModel->getTotalCount();

        // نسخه ۲: اطلاعات کامل + صفحه‌بندی
        return Response::success([
            'data' => $users, // تمام فیلدها
            'pagination' => [
                'current_page' => $page,
                'per_page' => $limit,
                'total' => $total,
                'total_pages' => ceil($total / $limit)
            ]
        ]);
    }

    // GET /v2/users/{id} - دریافت کاربر با اطلاعات کامل
    public function show($request, $params)
    {
        $user = $this->userModel->find($params[0]);
        
        if (!$user) {
            return Response::notFound();
        }

        // نسخه ۲: تمام فیلدها + اطلاعات اضافی
        return Response::success([
            'id' => $user['id'],
            'name' => $user['name'],
            'email' => $user['email'],
            'role' => $user['role'] ?? 'user',
            'created_at' => $user['created_at'],
            'updated_at' => $user['updated_at'],
            'profile_complete' => $this->isProfileComplete($user)
        ]);
    }

    // POST /v2/users - ایجاد کاربر با اعتبارسنجی پیشرفته
    public function store($request)
    {
        $data = $request->getBody();
        
        // اعتبارسنجی پیشرفته (نسخه ۲)
        $validation = $request->validate([
            'name' => 'required|min:3|max:100',
            'email' => 'required|email',
            'password' => 'required|min:8|strong',
            'role' => 'in:admin,user,guest'
        ]);

        if ($validation !== true) {
            return Response::error('Validation failed', 422, $validation);
        }

        $user = $this->userModel->create($data);
        
        return Response::created($user);
    }

    private function isProfileComplete($user)
    {
        // بررسی تکمیل بودن پروفایل
        $requiredFields = ['name', 'email', 'phone', 'address'];
        
        foreach ($requiredFields as $field) {
            if (empty($user[$field])) {
                return false;
            }
        }
        
        return true;
    }
}

🗺️ ثبت مسیرها با نسخه‌بندی

نحوه ثبت مسیرها در index.php با نسخه‌بندی:



🗺️
index.php (نسخه‌بندی)

PHP
8.2




<?php

// ========== بارگذاری فایل‌ها ==========
require_once __DIR__ . '/../src/Core/Router.php';
require_once __DIR__ . '/../src/Core/Request.php';
require_once __DIR__ . '/../src/Core/Response.php';

// بارگذاری کنترلرهای نسخه‌های مختلف
require_once __DIR__ . '/../src/Controllers/UserControllerv1.php';
require_once __DIR__ . '/../src/Controllers/UserControllerv2.php';
require_once __DIR__ . '/../src/Controllers/AuthController.php';

// ========== تنظیم مسیریاب ==========
$router = new Router();

// تنظیم نسخه‌های پشتیبانی شده
$router->setSupportedVersions(['v1', 'v2']);
$router->setDeprecatedVersions(['v1']);

// ========== مسیرهای نسخه ۱ (قدیمی) ==========
$router->add('GET', '/users', 'UserControllerv1', 'index', 'v1');
$router->add('GET', '/users/{id}', 'UserControllerv1', 'show', 'v1');
$router->add('POST', '/users', 'UserControllerv1', 'store', 'v1');

// ========== مسیرهای نسخه ۲ (جدید) ==========
$router->add('GET', '/users', 'UserControllerv2', 'index', 'v2');
$router->add('GET', '/users/{id}', 'UserControllerv2', 'show', 'v2');
$router->add('POST', '/users', 'UserControllerv2', 'store', 'v2');
$router->add('PUT', '/users/{id}', 'UserControllerv2', 'update', 'v2');
$router->add('DELETE', '/users/{id}', 'UserControllerv2', 'delete', 'v2');

// ========== مسیرهای احراز هویت (بدون نسخه) ==========
// این مسیرها مستقل از نسخه هستند و برای همه نسخه‌ها یکسانند
$router->add('POST', '/auth/register', 'AuthController', 'register', 'v1');
$router->add('POST', '/auth/login', 'AuthController', 'login', 'v1');
$router->add('POST', '/auth/register', 'AuthController', 'register', 'v2');
$router->add('POST', '/auth/login', 'AuthController', 'login', 'v2');

// ========== پردازش درخواست ==========
$request = new Request();
$response = $router->dispatch($request);

http_response_code($response->statusCode);
echo json_encode($response->body, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);

📋 مدیریت Deprecation و اعلان به کاربران

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



📋
Deprecation Manager

PHP
8.2




<?php

class DeprecationManager
{
    private static $deprecations = [
        'v1' => [
            'status' => 'deprecated',
            'deprecated_since' => '2026-01-01',
            'sunset_date' => '2026-12-31',
            'deprecation_message' => 'API v1 is deprecated. Please upgrade to v2.',
            'migration_guide' => 'https://rajestary.com/docs/api-migration-v1-to-v2'
        ]
    ];

    public static function addDeprecationHeaders($version)
    {
        if (isset(self::$deprecations[$version])) {
            $deprecation = self::$deprecations[$version];
            
            // هشدار در هدر
            header('Warning: 299 - "' . $deprecation['deprecation_message'] . '"');
            
            // هدر Sunset (طبق استاندارد RFC 8594)
            header('Sunset: ' . $deprecation['sunset_date']);
            
            // لینک راهنمای مهاجرت
            header('Link: <' . $deprecation['migration_guide'] . '>; rel="deprecation"; type="text/html"');
        }
    }

    public static function getDeprecationInfo($version)
    {
        return self::$deprecations[$version] ?? null;
    }

    public static function isDeprecated($version)
    {
        return isset(self::$deprecations[$version]) &&
               self::$deprecations[$version]['status'] === 'deprecated';
    }
}

// استفاده در مسیریاب
if (DeprecationManager::isDeprecated($version)) {
    DeprecationManager::addDeprecationHeaders($version);
}

🔄 استراتژی Backward Compatibility

Backward Compatibility به معنای حفظ سازگاری با نسخه‌های قبلی است. در اینجا چند استراتژی برای حفظ سازگاری:

استراتژی توضیح مثال
افزودن فیلدهای جدید فیلدهای جدید را به پاسخ اضافه کن بدون حذف فیلدهای قدیمی { "id": 1, "name": "یونس", "role": "admin" }
پارامترهای اختیاری پارامترهای جدید را اختیاری کن تا کاربران قدیمی مشکلی نداشته باشند ?include=profile
مقادیر پیش‌فرض برای فیلدهای جدید مقدار پیش‌فرض در نظر بگیر "role": "user"
نسخه‌بندی URI نسخه‌های مختلف را با مسیرهای جداگانه مدیریت کن /v1/users و /v2/users
Redirect درخواست‌های نسخه قدیمی را به نسخه جدید هدایت کن Redirect 301 از v1 به v2

🔴 خطاهای رایج در نسخه‌بندی

  • ❌ اشتباه: حذف ناگهانی یک نسخه بدون اعلان قبلی.
  • ✅ درست: حداقل ۶ ماه قبل از حذف، اعلان Deprecation بده.
  • ❌ اشتباه: پشتیبانی از نسخه‌های بسیار زیاد (بیش از ۳ نسخه).
  • ✅ درست: حداکثر ۲-۳ نسخه فعال نگه دار.
  • ❌ اشتباه: تغییر رفتار یک Endpoint بدون تغییر نسخه.
  • ✅ درست: هر تغییر غیرسازگار باید با یک نسخه جدید همراه باشد.
  • ❌ اشتباه: عدم مستندسازی تغییرات بین نسخه‌ها.
  • ✅ درست: یک Changelog واضح برای هر نسخه منتشر کن.

💎 نکات کلیدی درس

  • ✅ نسخه‌بندی به شما امکان تغییر API بدون شکستن کد کاربران را می‌دهد.
  • ✅ استراتژی URI Path (مانند /v1/users) محبوب‌ترین روش است.
  • ✅ از هدر Warning برای اطلاع‌رسانی Deprecation استفاده کن.
  • ✅ هر نسخه باید کنترلر مخصوص خود را داشته باشد.
  • ✅ Backward Compatibility برای حفظ کاربران قدیمی ضروری است.
  • ✅ برای هر نسخه، یک برنامه Sunset (زمان حذف) مشخص کن.
  • ✅ تغییرات بین نسخه‌ها را در مستندات Changelog ثبت کن.

🛠️ پروژه عملی درس هشتم

مهمان عزیز، حالا سیستم نسخه‌بندی را به API محصولات اضافه کن!

مسئله:

یک سیستم نسخه‌بندی کامل برای API محصولات پیاده‌سازی کن:

  • ✅ دو نسخه v1 و v2 برای API محصولات ایجاد کن.
  • ✅ نسخه v1 فقط اطلاعات پایه محصول را برگرداند.
  • ✅ نسخه v2 شامل اطلاعات کامل و اضافی باشد.
  • ✅ نسخه v1 را به عنوان Deprecated علامت‌گذاری کن.
  • ✅ هدرهای Warning و Sunset را به پاسخ‌ها اضافه کن.
  • ✅ یک مستند Changelog برای تغییرات بین نسخه‌ها بنویس.

🧪 راه‌حل پروژه (پاسخ)

مراحل پیاده‌سازی:

  • 1️⃣ دو کنترلر ProductControllerv1 و ProductControllerv2 ایجاد کن.
  • 2️⃣ مسیرهای هر نسخه را در index.php ثبت کن.
  • 3️⃣ کلاس DeprecationManager را برای مدیریت هدرها اضافه کن.
  • 4️⃣ نسخه v1 را Deprecated کن و هدرهای مربوطه را اضافه کن.
  • 5️⃣ تغییرات بین نسخه‌ها را در مستندات OpenAPI ثبت کن.

📝 تمرین‌های عملی

🧪 تمرین ۱ (ساده):

دو نسخه از یک Endpoint ساده ایجاد کن. نسخه v1 فقط id و name و نسخه v2 id، name، email و created_at را برگرداند.

🧪 تمرین ۲ (متوسط):

یک سیستم Redirect پیاده‌سازی کن که درخواست‌های نسخه v1 را به v2 هدایت کند و یک هشدار Deprecation نمایش دهد.

🧪 تمرین ۳ (چالشی):

یک سیستم A/B Testing با استفاده از نسخه‌بندی پیاده‌سازی کن. ۵۰٪ از کاربران به نسخه v1 و ۵۰٪ به نسخه v2 هدایت شوند. نتایج را در لاگ ثبت کن.


🏁 جمع‌بندی درس

مهمان عزیز، در این درس یاد گرفتی:

  • ✅ چرا نسخه‌بندی API مهم است و چه مزایایی دارد.
  • ✅ سه استراتژی اصلی نسخه‌بندی (URI، Query، Header).
  • ✅ چگونه نسخه‌بندی URI را در مسیریاب پیاده‌سازی کنی.
  • ✅ چگونه کنترلرهای مختلف برای نسخه‌های مختلف ایجاد کنی.
  • ✅ چگونه Deprecation را با هدرهای Warning و Sunset مدیریت کنی.
  • ✅ چگونه Backward Compatibility را حفظ کنی.

حالا API شما قابلیت تکامل و تغییر بدون شکستن کد کاربران را دارد. در درس بعدی، تست و دیباگ API حرفه‌ای را یاد می‌گیریم. آماده‌ای؟ 🚀


🗺️ نقشه راه دوره: شما اینجا هستید!

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

درس عنوان درس آنچه یاد می‌گیرید
۱ مفاهیم پایه API HTTP، REST، معماری Client-Server
۲ پیاده‌سازی RESTful API با PHP خام مسیریابی، متدها، پارامترها، پاسخ‌های JSON
۳ مدیریت داده‌ها و پایگاه‌داده اتصال PDO، CRUD، تراکنش‌ها، Pagination
۴ اعتبارسنجی و احراز هویت JWT، Roles/Permissions، Middleware
۵ امنیت API پیشرفته OWASP Top 10، SQLi، XSS، CSRF، Rate Limiting
۶ مستندسازی API با OpenAPI Swagger، OpenAPI Specification، مستندات تعاملی
۷ Caching و افزایش عملکرد Redis، ETag، Cache-Control، Query Optimization
۸ API Versioning و مدیریت چرخه حیات استراتژی‌های نسخه‌بندی، Deprecation، Backward Compatibility
۹ تست و دیباگ API حرفه‌ای PHPUnit، Mocking، Logging، Postman Collection
۱۰ پروژه نهایی: API فروشگاهی پروژه کامل فروشگاه اینترنتی با تمام قابلیت‌ها

🔗 لینک‌های مرتبط

👤
نویسنده
📅
تاریخ انتشار 30 مرداد 1405
🔄
آخرین بروزرسانی 30 مرداد 1405

نظر خود را بنویسید

با ثبت نظر، به بهبود محتوای ما کمک کنید

امتیاز شما به این مطلب (اختیاری)
برای امتیازدهی، روی ستاره‌ها کلیک کنید
نام شما در سایت نمایش داده می‌شود
ایمیل شما محفوظ می‌ماند
0 کاراکتر | حداقل ۱۰ کاراکتر
نظر سازنده و مفید بنویسید
ارسال دیدگاه: +۵ امتیاز
امتیازدهی: +۲ امتیاز
نشان شما: مبتدی
لطفاً از کلمات محترمانه استفاده کنید. دیدگاه‌های توهین‌آمیز حذف می‌شوند.
⚠️

هشدار مهم!

برای اتصال به درگاه پرداخت و انجام تراکنش، لطفاً VPN یا فیلترشکن خود را خاموش کنید.

⏳ ادامه در
5
ثانیه