مقالات علاء عامر

نقدم مجموعة شاملة من مقالات التعليمية الهامة في تطوير الويب لتحويل أفكارك إلى واقع رقمي

تطوير APIs في Laravel: بناء واجهات برمجية احترافية

Laravel 2026-01-01 علاء عامر

تطوير APIs في Laravel: بناء واجهات برمجية احترافية

دليل تخصصي من علاء عامر – مطور ومصمم مواقع وتطبيقات محترف

تطوير APIs في Laravel يتطلب فهماً عميقاً للمعايير الحديثة والممارسات الأمنية. تعلم كيفية بناء APIs قابلة للتطوير والصيانة.

2️⃣ API Controllers المتقدمة

Base API Controller:

<?php
// app/Http/Controllers/Api/BaseApiController.php
namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Pagination\LengthAwarePaginator;

class BaseApiController extends Controller
{
    /**
     * استجابة ناجحة
     */
    protected function successResponse($data = null, string $message = 'Success', int $code = 200): JsonResponse
    {
        $response = [
            'success' => true,
            'message' => $message,
            'data' => $data
        ];

        return response()->json($response, $code);
    }

    /**
     * استجابة خطأ
     */
    protected function errorResponse(string $message = 'Error', int $code = 400, $errors = null): JsonResponse
    {
        $response = [
            'success' => false,
            'message' => $message,
        ];

        if ($errors) {
            $response['errors'] = $errors;
        }

        return response()->json($response, $code);
    }

    /**
     * استجابة الموارد مع pagination
     */
    protected function paginatedResponse($resource, string $message = 'Data retrieved successfully'): JsonResponse
    {
        if ($resource instanceof LengthAwarePaginator) {
            return response()->json([
                'success' => true,
                'message' => $message,
                'data' => $resource->items(),
                'pagination' => [
                    'current_page' => $resource->currentPage(),
                    'last_page' => $resource->lastPage(),
                    'per_page' => $resource->perPage(),
                    'total' => $resource->total(),
                    'from' => $resource->firstItem(),
                    'to' => $resource->lastItem(),
                    'has_more_pages' => $resource->hasMorePages()
                ]
            ]);
        }

        return $this->successResponse($resource, $message);
    }

    /**
     * استجابة عدم وجود البيانات
     */
    protected function notFoundResponse(string $message = 'Resource not found'): JsonResponse
    {
        return $this->errorResponse($message, 404);
    }

    /**
     * استجابة عدم الصلاحية
     */
    protected function unauthorizedResponse(string $message = 'Unauthorized'): JsonResponse
    {
        return $this->errorResponse($message, 401);
    }

    /**
     * استجابة ممنوع
     */
    protected function forbiddenResponse(string $message = 'Forbidden'): JsonResponse
    {
        return $this->errorResponse($message, 403);
    }

    /**
     * استجابة خطأ validation
     */
    protected function validationErrorResponse($validator): JsonResponse
    {
        return $this->errorResponse(
            'Validation failed',
            422,
            $validator->errors()
        );
    }
}

Post API Controller:

<?php
// app/Http/Controllers/Api/PostController.php
namespace App\Http\Controllers\Api;

use App\Models\Post;
use App\Http\Resources\PostResource;
use App\Http\Resources\PostCollection;
use App\Http\Requests\Api\StorePostRequest;
use App\Http\Requests\Api\UpdatePostRequest;
use Illuminate\Http\Request;

class PostController extends BaseApiController
{
    public function __construct()
    {
        $this->middleware('auth:sanctum')->except(['index', 'show']);
        $this->middleware('throttle:60,1')->only(['store', 'update']);
    }

    /**
     * عرض قائمة المقالات
     */
    public function index(Request $request)
    {
        $query = Post::with(['author:id,name,avatar', 'category:id,name,slug'])
                    ->withCount(['comments', 'likes'])
                    ->published();

        // فلترة
        if ($request->filled('category')) {
            $query->whereHas('category', function($q) use ($request) {
                $q->where('slug', $request->category);
            });
        }

        if ($request->filled('author')) {
            $query->whereHas('author', function($q) use ($request) {
                $q->where('id', $request->author);
            });
        }

        if ($request->filled('search')) {
            $searchTerm = $request->search;
            $query->where(function($q) use ($searchTerm) {
                $q->where('title', 'LIKE', "%{$searchTerm}%")
                  ->orWhere('content', 'LIKE', "%{$searchTerm}%");
            });
        }

        // ترتيب
        $sortBy = $request->get('sort_by', 'published_at');
        $sortOrder = $request->get('sort_order', 'desc');

        if (in_array($sortBy, ['published_at', 'views_count', 'likes_count', 'title'])) {
            $query->orderBy($sortBy, $sortOrder);
        }

        // pagination
        $perPage = min($request->get('per_page', 15), 50);
        $posts = $query->paginate($perPage);

        return $this->paginatedResponse(
            new PostCollection($posts),
            'Posts retrieved successfully'
        );
    }

    /**
     * إنشاء مقال جديد
     */
    public function store(StorePostRequest $request)
    {
        $validated = $request->validated();
        $validated['user_id'] = auth()->id();
        $validated['slug'] = \Str::slug($validated['title']);

        // معالجة الصورة المميزة
        if ($request->hasFile('featured_image')) {
            $path = $request->file('featured_image')->store('posts', 'public');
            $validated['featured_image'] = $path;
        }

        $post = Post::create($validated);

        // ربط التصنيفات
        if ($request->filled('tags')) {
            $post->tags()->sync($request->tags);
        }

        $post->load(['author', 'category', 'tags']);

        return $this->successResponse(
            new PostResource($post),
            'Post created successfully',
            201
        );
    }

    /**
     * عرض مقال واحد
     */
    public function show(Post $post)
    {
        // التحقق من إمكانية العرض
        if ($post->status !== 'published' && $post->user_id !== auth()->id()) {
            return $this->notFoundResponse();
        }

        $post->load([
            'author:id,name,avatar,bio',
            'category:id,name,slug',
            'tags:id,name,slug',
            'comments' => function($query) {
                $query->with('user:id,name,avatar')
                      ->whereNull('parent_id')
                      ->latest()
                      ->limit(10);
            }
        ]);

        $post->loadCount(['comments', 'likes']);

        // زيادة عدد المشاهدات
        $post->incrementViews(auth()->user());

        // التحقق من إعجاب المستخدم الحالي
        if (auth()->check()) {
            $post->is_liked_by_user = $post->isLikedBy(auth()->user());
        }

        return $this->successResponse(
            new PostResource($post),
            'Post retrieved successfully'
        );
    }

    /**
     * تحديث مقال
     */
    public function update(UpdatePostRequest $request, Post $post)
    {
        // التحقق من الصلاحية
        if (!auth()->user()->can('update', $post)) {
            return $this->forbiddenResponse('You cannot update this post');
        }

        $validated = $request->validated();

        // تحديث الـ slug إذا تم تغيير العنوان
        if (isset($validated['title']) && $validated['title'] !== $post->title) {
            $validated['slug'] = \Str::slug($validated['title']);
        }

        // معالجة الصورة الجديدة
        if ($request->hasFile('featured_image')) {
            // حذف الصورة القديمة
            if ($post->featured_image) {
                \Storage::disk('public')->delete($post->featured_image);
            }

            $path = $request->file('featured_image')->store('posts', 'public');
            $validated['featured_image'] = $path;
        }

        $post->update($validated);

        // تحديث التصنيفات
        if ($request->has('tags')) {
            $post->tags()->sync($request->tags);
        }

        $post->load(['author', 'category', 'tags']);

        return $this->successResponse(
            new PostResource($post),
            'Post updated successfully'
        );
    }

    /**
     * حذف مقال
     */
    public function destroy(Post $post)
    {
        if (!auth()->user()->can('delete', $post)) {
            return $this->forbiddenResponse('You cannot delete this post');
        }

        // حذف الصورة المميزة
        if ($post->featured_image) {
            \Storage::disk('public')->delete($post->featured_image);
        }

        $post->delete();

        return $this->successResponse(
            null,
            'Post deleted successfully'
        );
    }

    /**
     * إعجاب بالمقال
     */
    public function like(Post $post)
    {
        $user = auth()->user();

        if ($post->isLikedBy($user)) {
            return $this->errorResponse('You already liked this post');
        }

        $post->like($user);

        return $this->successResponse([
            'likes_count' => $post->likes()->count(),
            'is_liked_by_user' => true
        ], 'Post liked successfully');
    }

    /**
     * إلغاء الإعجاب
     */
    public function unlike(Post $post)
    {
        $user = auth()->user();

        if (!$post->isLikedBy($user)) {
            return $this->errorResponse('You have not liked this post');
        }

        $post->unlike($user);

        return $this->successResponse([
            'likes_count' => $post->likes()->count(),
            'is_liked_by_user' => false
        ], 'Post unliked successfully');
    }

    /**
     * مشاركة المقال
     */
    public function share(Request $request, Post $post)
    {
        $platform = $request->input('platform', 'general');

        // تسجيل المشاركة للإحصائيات
        $post->shares()->create([
            'user_id' => auth()->id(),
            'platform' => $platform,
            'ip_address' => $request->ip()
        ]);

        $post->increment('shares_count');

        return $this->successResponse([
            'shares_count' => $post->shares_count,
            'share_url' => route('posts.show', $post->slug)
        ], 'Post shared successfully');
    }
}

4️⃣ API Authentication with Sanctum

إعداد Laravel Sanctum:

# تثبيت Sanctum
composer require laravel/sanctum

# نشر ملفات التكوين
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"

# تشغيل migrations
php artisan migrate

Auth API Controller:

<?php
// app/Http/Controllers/Api/AuthController.php
namespace App\Http\Controllers\Api;

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;
use App\Http\Requests\Api\RegisterRequest;
use App\Http\Requests\Api\LoginRequest;
use App\Http\Resources\UserResource;

class AuthController extends BaseApiController
{
    /**
     * تسجيل مستخدم جديد
     */
    public function register(RegisterRequest $request)
    {
        $validated = $request->validated();
        $validated['password'] = Hash::make($validated['password']);

        $user = User::create($validated);

        // إنشاء token
        $token = $user->createToken('API Token')->plainTextToken;

        return $this->successResponse([
            'user' => new UserResource($user),
            'token' => $token,
            'token_type' => 'Bearer'
        ], 'Registration successful', 201);
    }

    /**
     * تسجيل دخول
     */
    public function login(LoginRequest $request)
    {
        $credentials = $request->validated();

        $user = User::where('email', $credentials['email'])->first();

        if (!$user || !Hash::check($credentials['password'], $user->password)) {
            return $this->errorResponse('Invalid credentials', 401);
        }

        // التحقق من حالة المستخدم
        if ($user->status !== 'active') {
            return $this->errorResponse('Account is not active', 403);
        }

        // حذف tokens القديمة (اختياري)
        $user->tokens()->delete();

        // إنشاء token جديد
        $token = $user->createToken('API Token', [
            'posts:read',
            'posts:write',
            'comments:write'
        ])->plainTextToken;

        // تسجيل نشاط تسجيل الدخول
        $user->recordLogin($request);

        return $this->successResponse([
            'user' => new UserResource($user),
            'token' => $token,
            'token_type' => 'Bearer',
            'expires_in' => config('sanctum.expiration') ?
                          config('sanctum.expiration') * 60 : null
        ], 'Login successful');
    }

    /**
     * تسجيل خروج
     */
    public function logout(Request $request)
    {
        // حذف token الحالي
        $request->user()->currentAccessToken()->delete();

        return $this->successResponse(null, 'Logout successful');
    }

    /**
     * تسجيل خروج من جميع الأجهزة
     */
    public function logoutAll(Request $request)
    {
        // حذف جميع tokens
        $request->user()->tokens()->delete();

        return $this->successResponse(null, 'Logged out from all devices');
    }

    /**
     * معلومات المستخدم الحالي
     */
    public function user(Request $request)
    {
        $user = $request->user();
        $user->load(['roles:id,name', 'permissions:id,name']);

        return $this->successResponse(
            new UserResource($user),
            'User data retrieved'
        );
    }

    /**
     * تحديث الملف الشخصي
     */
    public function updateProfile(Request $request)
    {
        $request->validate([
            'name' => 'sometimes|string|max:255',
            'email' => 'sometimes|email|unique:users,email,' . auth()->id(),
            'phone' => 'sometimes|string|max:20',
            'bio' => 'sometimes|string|max:500',
            'avatar' => 'sometimes|image|mimes:jpeg,png,jpg|max:2048'
        ]);

        $user = auth()->user();
        $updateData = $request->only(['name', 'email', 'phone', 'bio']);

        // معالجة الصورة الشخصية
        if ($request->hasFile('avatar')) {
            // حذف الصورة القديمة
            if ($user->avatar) {
                \Storage::disk('public')->delete($user->avatar);
            }

            $path = $request->file('avatar')->store('avatars', 'public');
            $updateData['avatar'] = $path;
        }

        $user->update($updateData);

        return $this->successResponse(
            new UserResource($user),
            'Profile updated successfully'
        );
    }

    /**
     * تغيير كلمة المرور
     */
    public function changePassword(Request $request)
    {
        $request->validate([
            'current_password' => 'required|string',
            'new_password' => 'required|string|min:8|confirmed',
        ]);

        $user = auth()->user();

        if (!Hash::check($request->current_password, $user->password)) {
            return $this->errorResponse('Current password is incorrect', 400);
        }

        $user->update([
            'password' => Hash::make($request->new_password)
        ]);

        // حذف جميع tokens للأمان
        $user->tokens()->delete();

        return $this->successResponse(
            null,
            'Password changed successfully. Please login again.'
        );
    }

    /**
     * إرسال رابط استعادة كلمة المرور
     */
    public function forgotPassword(Request $request)
    {
        $request->validate(['email' => 'required|email']);

        $status = \Password::sendResetLink(
            $request->only('email')
        );

        if ($status === \Password::RESET_LINK_SENT) {
            return $this->successResponse(
                null,
                'Password reset link sent to your email'
            );
        }

        return $this->errorResponse('Unable to send reset link', 400);
    }

    /**
     * إعادة تعيين كلمة المرور
     */
    public function resetPassword(Request $request)
    {
        $request->validate([
            'token' => 'required',
            'email' => 'required|email',
            'password' => 'required|min:8|confirmed',
        ]);

        $status = \Password::reset(
            $request->only('email', 'password', 'password_confirmation', 'token'),
            function ($user, $password) {
                $user->forceFill([
                    'password' => Hash::make($password)
                ]);

                $user->save();
                $user->tokens()->delete(); // حذف جميع tokens
            }
        );

        if ($status === \Password::PASSWORD_RESET) {
            return $this->successResponse(
                null,
                'Password reset successfully'
            );
        }

        return $this->errorResponse('Invalid reset token', 400);
    }
}

💡 أفضل الممارسات لـ APIs

  1. استخدم HTTP Status Codes الصحيحة
  2. طبق Rate Limiting لمنع إساءة الاستخدام
  3. وثق APIs باستخدام Swagger/OpenAPI
  4. استخدم API Versioning للتوافق مع الإصدارات القديمة
  5. طبق Input Validation الشاملة
  6. استخدم HTTPS دائماً
  7. راقب الأداء والاستخدام بانتظام

الخطوة التالية

تعلم Testing في Laravel لضمان جودة وموثوقية تطبيقاتك.

📩 هل تحتاج مساعدة في تطوير APIs متقدمة؟

Laravel API Development REST API JSON Authentication API Resources Swagger
قسم المقالة
Laravel

تطوير APIs في Laravel: بناء واجهات برمجية احترافية

دليل شامل لتطوير REST APIs في Laravel باستخدام أحدث المعايير، من التصميم الأساسي إلى الحماية المتقدمة والتوثيق.

تطوير APIs في Laravel: بناء واجهات برمجية احترافية
01

التواصل والاستشارة

تواصل مباشر عبر الواتساب أو الهاتف لفهم احتياجات مشروعك بدقة.

02

التخطيط والجدولة

وضع خطة عمل واضحة مع جدول زمني محدد لكل مرحلة من المشروع.

03

البرمجة والتطوير

تطوير المشروع بأحدث التقنيات لضمان الأداء والأمان العاليين.

04

المراجعة والتسليم

ختبار شامل ومراجعة دقيقة قبل التسليم النهائي للمشروع.

علاء عامر
علاء عامر

مطور ويب محترف بخبرة تزيد عن 10 سنوات في بناء حلول رقمية مبتكرة.

هل تحتاج هذه الخدمة؟

تواصل معي الآن للحصول على استشارة مجانية وعرض سعر

تواصل عبر واتساب رضاكم هو هدفنا الأسمى

عروض إضافية

  • صيانة وتحديث المواقع

    نحافظ على موقعك آمنًا ومحدّثًا دائمًا

  • ربط الأنظمة وواجهات البرمجة

    نربط أنظمتك بواجهات برمجية قوية ومرنة

  • تصميم وتحسين قواعد البيانات

    استعلامات أسرع وهيكلة أوضح وأخطاء أقل

  • تأمين المواقع والحماية المتقدمة

    حماية موقعك من التهديدات السيبرانية

  • أتمتة العمليات والمهام البرمجية

    نؤتمت المهام المتكررة ونوفّر وقتك دائمًا

لديك استفسار؟

اتصل بنا الآن

00201014714795

راسلنا عبر البريد الإلكتروني

[email protected]