التعامل مع API في Laravel – الجزء الثامن: إنشاء API Documentation باستخدام Scribe
بعد الانتهاء من بناء REST API، لا ينتهي العمل عند جعل Endpoints تعمل بشكل صحيح فقط، بل يجب أيضًا توثيقها بطريقة يستطيع مطور Frontend أو تطبيق الهاتف فهمها واستخدامها بسهولة.
عندما يستلم مطور آخر API بدون Documentation، سيحتاج إلى معرفة الكثير من التفاصيل بشكل يدوي، مثل:
- ما هي Endpoints المتاحة؟
- ما نوع HTTP Method لكل Endpoint؟
- ما هي Parameters المطلوبة؟
- ما الحقول الإجبارية والاختيارية؟
- ما هي Headers المطلوبة؟
- هل Endpoint يحتاج Authentication؟
- ما شكل JSON Response؟
- ما هي HTTP Status Codes المتوقعة؟
- كيف يتم رفع الملفات؟
لهذا تعتبر API Documentation جزءًا أساسيًا من أي API احترافي.
توجد عدة أدوات لإنشاء Documentation، وفي هذا الدرس سنستخدم:
Scribeوهي أداة مخصصة لتوليد API Documentation مباشرة من تطبيق Laravel، ويمكنها قراءة Routes وControllers وForm Requests وValidation Rules وإنشاء Documentation قابلة للقراءة والاستخدام.
جدول المحتويات
- ما هي API Documentation؟
- لماذا نحتاج إلى توثيق API؟
- ما هي Scribe؟
- ماذا يمكن أن تنشئ Scribe؟
- تثبيت Scribe
- نشر ملف الإعدادات
- ملف config/scribe.php
- اختيار نوع Documentation
- تحديد Routes التي سيتم توثيقها
- إعداد APP_URL
- توليد Documentation
- عرض Documentation
- تسمية Endpoints
- تنظيم Endpoints باستخدام Groups
- توثيق Body Parameters
- توثيق Query Parameters
- توثيق URL Parameters
- توثيق Headers
- استخراج Parameters من Form Request
- توثيق رفع الملفات
- توثيق Responses
- توثيق Authentication
- إنشاء Postman Collection
- إنشاء OpenAPI Specification
- إضافة Logo ومعلومات المشروع
- إعادة توليد Documentation
- حماية Documentation في Production
- مثال متكامل
- أفضل الممارسات
- ملخص الدرس
- الخلاصة
ما هي API Documentation؟
API Documentation هي مرجع يشرح للمطورين كيفية التعامل مع API.
مثلًا إذا كان لدينا Endpoint:
POST /api/v1/brandsفإن Documentation الجيدة يجب أن توضح:
- أن Method هي POST.
- أن Endpoint ينشئ Brand جديدًا.
- أن الحقل name مطلوب.
- أن photo اختيارية مثلًا.
- ما نوع كل حقل.
- ما Headers المطلوبة.
- ما شكل Response عند النجاح.
- ما الأخطاء المحتملة.
بدل أن يحتاج مطور Frontend إلى قراءة Source Code، يستطيع الاعتماد على Documentation.
لماذا نحتاج إلى توثيق API؟
API Documentation مهمة حتى لو كنت أنت من قام ببرمجة Backend وFrontend.
بعد عدة أشهر قد لا تتذكر جميع Endpoints والParameters والتفاصيل الدقيقة.
وتصبح أهم عندما يعمل على المشروع عدة مطورين:
Backend Developer
|
v
API Documentation
|
+-------- Frontend Developer
|
+-------- Android Developer
|
+-------- iOS Developer
|
+-------- External Integrationوبذلك تصبح Documentation بمثابة Contract واضح بين Backend والأنظمة التي تستخدم API.
ما هي Scribe؟
Scribe هي أداة لإنشاء API Documentation من Laravel Application.
تقوم بقراءة معلومات موجودة بالفعل داخل المشروع مثل:
- Routes.
- Controllers.
- Form Requests.
- Validation Rules.
- API Resources.
- PHP DocBlocks.
- PHP Attributes.
ثم تستخدم هذه المعلومات لإنشاء Documentation منظمة.
هذا يقلل كمية التوثيق التي يجب كتابتها يدويًا ويحافظ على Documentation أقرب إلى الكود الفعلي.
ماذا يمكن أن تنشئ Scribe؟
Scribe لا تنشئ مجرد قائمة بسيطة بالـRoutes.
يمكنها إنشاء:
- صفحة HTML Documentation.
- أمثلة Requests.
- أمثلة Responses.
- توثيق Parameters.
- توثيق Authentication.
- تقسيم Endpoints إلى Groups.
- واجهة Try It Out لاختبار بعض Requests من Documentation.
- Postman Collection.
- OpenAPI Specification.
وهذا يجعلها مناسبة لإنشاء Documentation يمكن إرسالها مباشرة إلى الفريق الذي سيستهلك API.
تثبيت Scribe
نبدأ بتثبيت Package باستخدام Composer:
composer require knuckleswtf/scribeبعد انتهاء Composer تصبح Scribe متاحة داخل تطبيق Laravel.
نشر ملف إعدادات Scribe
بعد التثبيت نقوم بنشر Configuration:
php artisan vendor:publish --tag=scribe-configسيتم إنشاء الملف:
config/scribe.phpوهو الملف الرئيسي الذي نستخدمه للتحكم في طريقة توليد Documentation.
ملف config/scribe.php
يحتوي ملف:
config/scribe.phpعلى معظم إعدادات Documentation.
من خلاله نستطيع التحكم في أمور مثل:
- نوع Documentation.
- Routes التي سيتم تضمينها.
- اسم API.
- Base URL.
- Logo.
- Authentication.
- Example Requests.
- Groups.
- Response Calls.
اختيار نوع Documentation
من أهم إعدادات Scribe:
'type'وتوجد طريقتان أساسيتان لتوليد Documentation.
static
'type' => 'static',في هذا الوضع يتم إنشاء ملفات HTML وAssets ثابتة.
عادةً يتم وضعها داخل:
public/docsهذا الخيار بسيط جدًا عندما نريد Documentation عامة.
laravel
'type' => 'laravel',في هذا الوضع يتم تقديم Documentation من داخل Laravel نفسه.
ميزة هذه الطريقة أننا نستطيع تطبيق Middleware على Documentation، وهذا مفيد إذا كانت API Documentation خاصة ولا نريد أن يراها أي شخص.
تحديد Routes التي سيتم توثيقها
من أهم الأمور إخبار Scribe بالـRoutes التي نريد تضمينها.
داخل:
config/scribe.phpسنجد إعدادًا قريبًا من:
'routes' => [
[
'match' => [
'domains' => ['*'],
'prefixes' => ['api/*'],
],
'include' => [
//
],
'exclude' => [
//
],
],
],القيمة:
'prefixes' => ['api/*']تعني أن Scribe ستبحث عن Routes التي تبدأ بـ:
api/مثل:
/api/v1/brands
/api/v1/products
/api/loginلكن Route مثل:
/admin/dashboardلن يتم تضمينه وفق هذا الإعداد.
إعداد APP_URL
من المهم أن تكون قيمة:
APP_URLصحيحة في Environment.
في بيئة التطوير يمكن أن تكون مثلًا:
APP_URL=http://localhost:8000وفي Production:
APP_URL=https://api.example.comتستخدم هذه القيمة في عدة أماكن داخل Laravel، ويمكن أن تؤثر على URLs التي تظهر في Documentation حسب Configuration المستخدمة.
توليد API Documentation
بعد ضبط الإعدادات يمكن توليد Documentation باستخدام:
php artisan scribe:generateستقوم Scribe عندها بقراءة Routes ومعلومات Endpoints وإنشاء Documentation.
يمكن تنفيذ هذا الأمر مرة أخرى كلما قمنا بتعديل API أو Documentation.
عرض Documentation
طريقة الوصول إلى Documentation تعتمد على قيمة:
typeStatic Documentation
إذا كان النوع:
staticيتم إنشاء ملفات Documentation الثابتة داخل:
public/docsومن بينها ملف:
index.htmlLaravel Documentation
إذا كان النوع:
laravelيمكن عادةً الوصول إلى Documentation من:
/docsبحسب إعدادات Scribe.
تسمية Endpoints بطريقة واضحة
Scribe تحاول استخراج معلومات Endpoint تلقائيًا، لكن يمكننا إضافة Description أوضح باستخدام DocBlock فوق دالة Controller.
مثلًا:
/**
* Get brands.
*
* Get a list of all available brands.
*/
public function index()
{
return BrandResource::collection(
Brand::query()
->latest()
->get()
);
}السطر الأول:
Get brands.يستخدم كعنوان مختصر للـEndpoint.
أما النص التالي فيستخدم كشرح أكثر تفصيلًا.
تنظيم Endpoints باستخدام Groups
عندما يحتوي API على عشرات Endpoints، فإن عرضها جميعًا في قائمة واحدة يجعل Documentation صعبة القراءة.
يمكن استخدام:
@groupلتقسيم Endpoints حسب الوظيفة.
مثلًا فوق BrandController:
/**
* @group Brands
*
* APIs for managing brands.
*/
class BrandController extends Controller
{
//
}وتصبح Endpoints الخاصة بالـBrands موجودة تحت Group باسم:
Brandsكما يمكن إنشاء Groups أخرى:
Authentication
Users
Products
Orders
Payments
Uploadsوهذا يجعل Documentation أكثر تنظيمًا.
توثيق Body Parameters
لنفترض أن لدينا Endpoint:
POST /api/v1/brandsويحتاج إلى حقل:
nameيمكن توثيقه باستخدام:
@bodyParamمثل:
/**
* Create brand.
*
* Create a new brand.
*
* @bodyParam name string required The brand name. Example: Apple
*/
public function store(
BrandStoreRequest $request
) {
//
}يتكون تعريف Body Parameter من:
@bodyParam
name
string
required
description
Exampleوبهذا يستطيع مطور Frontend معرفة أن:
- اسم الحقل هو name.
- نوعه string.
- الحقل required.
- يوجد Example للقيمة.
توثيق Query Parameters
إذا كان لدينا Endpoint يدعم Pagination أو Filtering:
GET /api/v1/products?page=2&search=laptopيمكن استخدام:
@queryParamمثل:
/**
* Get products.
*
* @queryParam page int The page number. Example: 2
* @queryParam search string Search by product name. Example: laptop
*/
public function index()
{
//
}توثيق URL Parameters
إذا كان لدينا:
GET /api/v1/brands/{brand}يمكن توضيح Path Parameter باستخدام:
@urlParamمثلًا:
/**
* Get brand.
*
* @urlParam brand int required The brand ID. Example: 10
*/
public function show(Brand $brand)
{
return new BrandResource($brand);
}وبذلك يعرف مستخدم Documentation أن:
{brand}يجب استبدالها بـBrand ID.
توثيق Headers
بعض Endpoints تحتاج إلى Headers معينة.
مثل:
Accept: application/jsonأو:
Accept-Language: arأو:
X-API-Key: ...من المهم أن تظهر هذه المعلومات في Documentation حتى يعرف Client ما يجب إرساله.
استخراج Parameters من Form Request تلقائيًا
من أفضل ميزات Scribe أنها تستطيع الاستفادة من Validation Rules الموجودة داخل Laravel.
لنفترض أن لدينا:
class BrandStoreRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => [
'required',
'string',
'max:255',
],
'photo' => [
'nullable',
'image',
'max:2048',
],
];
}
}Scribe تستطيع استخراج معلومات عن Parameters من Validation Rules في Form Request، لذلك لا نحتاج دائمًا إلى تكرار كل Rule داخل DocBlock.
لكن يمكن إضافة Annotations عندما نريد:
- Description أفضل.
- Example محدد.
- شرح خاص للمطور.
- توضيح قيم معينة.
توثيق رفع الملفات
في الجزء الثاني من السلسلة تعلمنا رفع الملفات من REST API.
يمكن أيضًا توثيق File Parameter في Scribe.
مثل:
/**
* Create brand.
*
* @bodyParam name string required The brand name. Example: Apple
* @bodyParam photo file The brand image.
*/
public function store(
BrandStoreRequest $request
) {
//
}نوع:
fileيخبر Scribe أن Parameter عبارة عن ملف.
عند وجود File Parameter تستطيع Scribe التعامل مع Example Request باعتباره:
multipart/form-dataتوثيق API Responses
Documentation الجيدة لا تشرح Request فقط.
يجب أيضًا أن توضح Response الذي سيحصل عليه Client.
مثلًا عند طلب:
GET /api/v1/brands/10يمكن أن تكون الاستجابة:
{
"data": {
"id": 10,
"name": "Apple"
}
}Scribe تستطيع إنشاء Sample Responses بعدة طرق، ومنها الاستفادة من API Resources أو تشغيل Response Calls وفق Configuration.
كلما كانت أمثلة Response واقعية، أصبح التعامل مع API أسهل على المطورين الآخرين.
توثيق Authentication
إذا كانت Endpoints محمية، فمن المهم أن يظهر ذلك بوضوح في Documentation.
مثلًا API يستخدم:
Authorization: Bearer TOKENأو:
X-API-Key: API_KEYيجب إعداد Scribe بحيث تعرض Authentication المطلوبة وطريقة إرسال Credentials.
لا تضع Token حقيقية أو API Key حقيقية داخل Documentation.
استخدم Example فقط مثل:
Authorization: Bearer YOUR_ACCESS_TOKENإنشاء Postman Collection
ميزة مهمة في Scribe هي إمكانية إنشاء Postman Collection بجانب Documentation.
هذا مفيد جدًا لأن مطور Frontend أو تطبيق الهاتف يستطيع استيراد Collection إلى Postman وتجربة Endpoints مباشرة بدل إنشاء كل Request يدويًا.
يمكن أن تحتوي Collection على:
- Endpoints.
- HTTP Methods.
- Parameters.
- Headers.
- Example Requests.
وهذا يجعل تسليم API إلى فريق آخر أسهل بكثير.
إنشاء OpenAPI Specification
Scribe تستطيع أيضًا إنشاء:
OpenAPI SpecificationOpenAPI عبارة عن صيغة معيارية لوصف APIs.
وجود OpenAPI Specification يسمح باستخدام Documentation مع عدد كبير من الأدوات الأخرى التي تفهم OpenAPI.
وهذا يجعل Documentation التي يتم إنشاؤها بواسطة Scribe مفيدة خارج واجهة Scribe نفسها.
إضافة Logo ومعلومات المشروع
يمكن تخصيص شكل Documentation ومعلوماتها العامة من:
config/scribe.phpومن المعلومات التي يمكن تخصيصها:
- عنوان API.
- Introduction.
- Base URL.
- Logo.
- Authentication Information.
- Example Languages.
من الأفضل كتابة مقدمة توضح للمطور الذي يستخدم API ما هو النظام الذي يتعامل معه.
مثلًا:
This documentation describes the REST API
for the Example application.كما يمكن إضافة Logo للمشروع حتى تبدو Documentation جزءًا من النظام نفسه.
إعادة توليد Documentation بعد التعديل
عند تعديل Controller أو Route أو Documentation Annotation، يجب إعادة تشغيل:
php artisan scribe:generateحتى يتم توليد Documentation المحدثة.
يمكن تشغيل الأمر كلما تم تحديث API.
وفي المشاريع الأكبر يمكن إدخال هذه العملية ضمن Deployment أو CI/CD Pipeline إذا كان ذلك مناسبًا لأسلوب العمل.
حماية API Documentation في Production
هناك نقطة مهمة يجب الانتباه إليها:
ليس كل API Documentation يجب أن تكون Public.
إذا كانت Documentation تحتوي على معلومات عن:
- Internal Endpoints.
- Administration APIs.
- Internal Integrations.
- Sensitive Operations.
- طرق Authentication الداخلية.
فقد نريد منع الوصول إليها من أي شخص على الإنترنت.
إذا اخترنا Scribe Documentation من نوع:
laravelفيمكن تقديم Documentation عبر Laravel، وبالتالي يمكن إضافة Middleware مناسب لحمايتها.
أما النوع:
staticفينشئ ملفات ثابتة في Public Directory، ولذلك لا تمر Requests الخاصة بها عبر Laravel Middleware.
هذه نقطة مهمة جدًا عند اختيار نوع Documentation.
مثال متكامل لتوثيق Brands API
لنفترض أن لدينا Controller:
<?php
namespace App\Http\Controllers\Api\V1;
use App\Http\Controllers\Controller;
use App\Http\Requests\BrandStoreRequest;
use App\Http\Resources\BrandResource;
use App\Models\Brand;
/**
* @group Brands
*
* APIs for managing brands.
*/
class BrandController extends Controller
{
/**
* Get brands.
*
* Get a list of all brands.
*
* @queryParam page int The page number. Example: 1
*/
public function index()
{
return BrandResource::collection(
Brand::query()
->latest()
->paginate()
);
}
/**
* Create brand.
*
* Create a new brand.
*
* @bodyParam name string required The brand name. Example: Apple
* @bodyParam photo file The brand image.
*/
public function store(
BrandStoreRequest $request
) {
$data = $request->validated();
if ($request->hasFile('photo')) {
$data['photo'] = $request
->file('photo')
->store('brands', 'public');
}
$brand = Brand::create($data);
return new BrandResource($brand);
}
/**
* Get brand.
*
* Get the details of a specific brand.
*
* @urlParam brand int required The brand ID. Example: 10
*/
public function show(Brand $brand)
{
return new BrandResource($brand);
}
/**
* Delete brand.
*
* Delete a specific brand.
*
* @urlParam brand int required The brand ID. Example: 10
*/
public function destroy(Brand $brand)
{
$brand->delete();
return response()->noContent();
}
}ثم لدينا Route:
Route::prefix('v1')
->group(function () {
Route::apiResource(
'brands',
BrandController::class
);
});وفي Scribe Configuration:
'routes' => [
[
'match' => [
'domains' => ['*'],
'prefixes' => ['api/*'],
],
'include' => [],
'exclude' => [],
],
],ثم نقوم بتشغيل:
php artisan scribe:generateفتقوم Scribe بتوليد Documentation تحتوي على Endpoints الخاصة بـBrands، والParameters والأمثلة والمعلومات التي تم استخراجها من التطبيق.
أفضل الممارسات عند إنشاء API Documentation
لا تكتب عنوان Endpoint فقط
اكتب Description توضح ما الذي تقوم به العملية.
أضف Examples واقعية
بدل:
Example: stringاستخدم:
Example: Appleوثق الحقول الاختيارية والإجبارية
حتى يعرف Client ما الذي يجب إرساله.
استخدم Groups
قسم Documentation إلى:
Authentication
Users
Brands
Products
Orders
Paymentsبدل وضع كل Endpoints داخل مجموعة واحدة.
استفد من Form Requests
إذا كانت Validation Rules موجودة بالفعل فلا تكرر كل شيء يدويًا بدون حاجة.
وثق Authentication
يجب أن يعرف Client أي Endpoints تحتاج إلى Token وكيف يتم إرسالها.
وثق Error Responses
لا تعرض فقط مثال النجاح.
يجب أن يعرف Client كيف يتعامل مع حالات مثل:
401 Unauthorized
403 Forbidden
404 Not Found
422 Unprocessable Content
429 Too Many Requestsلا تستخدم Credentials حقيقية في الأمثلة
لا تضع:
- Access Token حقيقية.
- API Keys حقيقية.
- Passwords حقيقية.
- بيانات مستخدم حقيقية.
حدث Documentation مع API
Documentation قديمة أحيانًا أسوأ من عدم وجود Documentation، لأنها تجعل Client يعتمد على معلومات غير صحيحة.
لذلك عند تغيير API يجب تحديث Documentation وإعادة تشغيل:
php artisan scribe:generateاحمِ Documentation الداخلية
إذا كانت Documentation خاصة، لا تنشرها Public بدون Authentication مناسب.
ملخص الدرس
| المفهوم | الوصف |
|---|---|
| Scribe | أداة لتوليد API Documentation من تطبيق Laravel. |
| scribe:generate | الأمر المستخدم لتوليد Documentation. |
| config/scribe.php | ملف إعدادات Scribe الرئيسي. |
| static | إنشاء Documentation كملفات HTML ثابتة. |
| laravel | تقديم Documentation من خلال Laravel وإمكانية استخدام Middleware. |
| routes.match.prefixes | تحديد Route Prefixes التي ستقوم Scribe بتوثيقها. |
| @group | تقسيم Endpoints إلى مجموعات. |
| @bodyParam | توثيق Parameters الموجودة في Request Body. |
| @queryParam | توثيق Query String Parameters. |
| @urlParam | توثيق Route Parameters. |
| Form Request | يمكن لـScribe استخراج معلومات Parameters وValidation منه. |
| Postman Collection | ملف يمكن استيراده إلى Postman لتجربة API. |
| OpenAPI | Specification معيارية لوصف API. |
الخلاصة
بعد الانتهاء من تطوير REST API، تعتبر Documentation واحدة من أهم الخطوات قبل تسليم API إلى Frontend Developer أو Mobile Developer أو أي نظام خارجي.
في هذا الدرس استخدمنا:
Scribeلإنشاء API Documentation مباشرة من مشروع Laravel.
بدأنا بتثبيت Package:
composer require knuckleswtf/scribeثم نشر Configuration:
php artisan vendor:publish --tag=scribe-configوبعد إعداد:
config/scribe.phpحددنا Routes التي نريد توثيقها باستخدام:
'prefixes' => ['api/*']ثم قمنا بتوليد Documentation بواسطة:
php artisan scribe:generateكما تعلمنا كيفية جعل Documentation أكثر وضوحًا باستخدام:
@group
@bodyParam
@queryParam
@urlParamوتعرفنا أيضًا على أن Scribe تستطيع استخراج معلومات من Form Requests، وإنشاء Sample Responses، وPostman Collection، وOpenAPI Specification.
الهدف من Documentation ليس فقط عرض أسماء Endpoints، بل إنشاء مرجع كامل يستطيع أي مطور من خلاله فهم API واستخدامه بدون الحاجة إلى قراءة Source Code أو سؤال Backend Developer عن كل Request.
كلما كانت Documentation واضحة ومحدثة، أصبح تطوير Frontend وتطبيقات الهاتف وعمليات Integration أسرع وأسهل وأقل عرضة للأخطاء.
شكرا جزيلا
شرح احترافي جدا
ماشاء الله عليك ايثار، والله مقالات رائعة. سلمت اناملك
انا كنت محتاج دة جدًا، شكرًا بجد ربنا يجزيك خير