اتخطّى للمحتوى

المرحلة 03 · الـ APIs والتكاملدرس 12 من 219 دقيقة قراءةآخر تحديث:

Lesson 12 / 21

REST APIFull CRUD.

هنبني REST API كامل لنفس الـ entity ("Ticket") — Create, Read, Update, Delete — خطوة بخطوة بالشرح. الجميل إن Magento بيبني الـ REST أوتوماتيك فوق الـ service contracts، فالشغل أقل مما تتخيّل.

● Step by step webapi.xml Repository ACL Data Interface

Magento 2 بيبني الـ REST API فوق الـ service contracts: بتعرّف Data Interface و Repository Interface، وبتربط كل URL و HTTP method بـ method في الـ repository جوّه etc/webapi.xml، مع صلاحية معرّفة في acl.xml. وMagento بيتولّى الـ routing وتحويل الـ JSON للـ objects والعكس، وبتختبر الـ endpoints بـ access token.

// الفكرة الأساسية في REST، أنت مش بتكتب controllers. بتعرّف الـ routes في webapi.xml وبتربطها بـ methods موجودة في الـ repository. Magento بيتولّى الباقي: الـ routing، تحويل الـ JSON، والـ authorization. عشان كده الـ service contract لازم يكون معمول صح.
00

نظرة عامة والملفات

الصورة الكاملة قبل الكود: إزاي REST بيشتغل في Magento وأنهي ملفات محتاجينها.

الفكرة

REST في Magento مبني على مبدأ: "عرّف العقد، والباقي أوتوماتيك". بتكتب interface للـ repository، وبتقول في webapi.xml "الـ URL ده بينادي الـ method دي" — و Magento يعمل كل حاجة.

ليه ده أبسط من GraphQL

في GraphQL بتكتب resolver لكل عملية. في REST، لو الـ repository جاهز، بتكتب XML بس — مفيش كود resolver. Magento بيعمل الـ serialization من والـ Data interface أوتوماتيك.

i
كل endpoints الـ REST بتبدأ بـ /rest/. الـ URL الكامل بيكون: /rest/<store>/V1/<your-path> — والـ store اختياري (لو محذوف بياخد الافتراضي).
GET/V1/tickets/:idقراءة واحدة
GET/V1/ticketsقراءة قائمة
POST/V1/ticketsإنشاء
PUT/V1/tickets/:idتعديل
DELETE/V1/tickets/:idحذف
i
لاحظ إزاي نفس الـ path (/tickets/:id) بيعمل عمليات مختلفة حسب الـ HTTP verb — ده جوهر تصميم الـ REST.
Vendor/Module/ ├── Api/ │ ├── TicketRepositoryInterface.php # العمليات │ └── Data/ │ └── TicketInterface.php # البيانات ├── Model/ │ ├── TicketRepository.php # التنفيذ │ └── Ticket.php # الـ model └── etc/ ├── webapi.xml # الـ routes ├── di.xml # preferences └── acl.xml # الصلاحيات
• • •
01

Data Interface

بيوصّف شكل بيانات الـ Ticket. منه Magento بيعرف يعمل serialization للـ JSON.

وظيفته

يعرّف الـ getters والـ setters لكل حقل. Magento بيقرا الـ return types عشان يبني الـ JSON response بالأنواع الصح.

Api/Data/TicketInterface.phpphp
interface TicketInterface
{
    const ENTITY_ID = 'entity_id';
    const TITLE     = 'title';
    const STATUS    = 'status';

    public function getId();
    public function setId($id);

    public function getTitle(): ?string;
    public function setTitle(string $title): TicketInterface;

    public function getStatus(): ?string;
    public function setStatus(string $status): TicketInterface;
}
i
الـ return types مهمة جدًا في REST: ?string بيقول لـ Magento إن الحقل ده string وممكن يكون null. ده اللي بيحدد شكل الـ JSON الخارج.
• • •
02

Repository Interface

قلب الـ REST API. كل عملية REST بتربط بـ method هنا. لازم تكون typed بدقة.

وظيفته

يعرّف العمليات: save (بتخدم create + update)، getById، getList، وdelete. كل واحدة هتتربط بـ endpoint.

Api/TicketRepositoryInterface.phpphp
interface TicketRepositoryInterface
{
    public function save(
        TicketInterface $ticket
    ): TicketInterface;

    public function getById(
        int $id
    ): TicketInterface;

    public function getList(
        SearchCriteriaInterface $criteria
    ): TicketSearchResultsInterface;

    public function delete(
        TicketInterface $ticket
    ): bool;

    public function deleteById(
        int $id
    ): bool;
}
ASKليه فيه delete و deleteById الاتنين؟
الإجابة: delete بياخد object كامل (مفيد جوّه الكود). deleteById بياخد id بس — وده الأنسب للـ REST لأن الـ DELETE endpoint بيبعت الـ id في الـ URL مش object كامل.
!
الـ typing هنا مش رفاهية — Magento بيعتمد عليه بالكامل عشان يعمل serialize للـ REST. لو الـ types غلط أو ناقصة، الـ API مش هيشتغل صح.
• • •
03

webapi.xml — الـ routes

الملف السحري. هنا بتربط كل URL + HTTP verb بـ method في الـ repository. ده أهم ملف.

مكوّنات كل route

كل <route> فيه: الـ url والـ method (الـ HTTP verb)، الـ <service> (الـ interface و method)، والـ <resources> (صلاحية الوصول).

etc/webapi.xmlxml
<routes>
  <!-- READ one -->
  <route url="/V1/tickets/:id" method="GET">
    <service class="...\TicketRepositoryInterface"
             method="getById"/>
    <resources>
      <resource ref="Vendor_Module::view"/>
    </resources>
  </route>

  <!-- READ list -->
  <route url="/V1/tickets" method="GET">
    <service class="...\TicketRepositoryInterface"
             method="getList"/>
    <resources>
      <resource ref="Vendor_Module::view"/>
    </resources>
  </route>

  <!-- CREATE -->
  <route url="/V1/tickets" method="POST">
    <service class="...\TicketRepositoryInterface"
             method="save"/>
    <resources>
      <resource ref="Vendor_Module::manage"/>
    </resources>
  </route>

  <!-- UPDATE -->
  <route url="/V1/tickets/:id" method="PUT">
    <service class="...\TicketRepositoryInterface"
             method="save"/>
    <resources>
      <resource ref="Vendor_Module::manage"/>
    </resources>
  </route>

  <!-- DELETE -->
  <route url="/V1/tickets/:id" method="DELETE">
    <service class="...\TicketRepositoryInterface"
             method="deleteById"/>
    <resources>
      <resource ref="Vendor_Module::manage"/>
    </resources>
  </route>
</routes>
i
الـ :id في الـ URL بيتطابق أوتوماتيك مع الـ parameter اسمه $id في الـ method. لازم الأسماء تتطابق عشان الربط يشتغل.
ASKيعني إيه resource ref="anonymous"؟
الإجابة: لو حطيت ref="anonymous" بدل صلاحية، الـ endpoint بيبقى عام (public) — أي حد يقدر يوصله من غير token. استخدمه بحذر شديد، بس للبيانات العامة زي قائمة المنتجات.

الـ resources اللي استخدمناها فوق (view وmanage) لازم تكون معرّفة في الـ acl.xml.

etc/acl.xmlxml
<resources>
  <resource id="Magento_Backend::admin">
    <resource id="Vendor_Module::main" title="Tickets">
      <resource id="Vendor_Module::view"
        title="View Tickets"/>
      <resource id="Vendor_Module::manage"
        title="Manage Tickets"/>
    </resource>
  </resource>
</resources>
• • •
04

Read — GET

القراءة جاهزة بمجرد ما عرّفنا الـ routes. مفيش كود إضافي — الـ repository موجود.

مفيش كود جديد

الـ route بتاع الـ GET مربوط بـ getById وgetList اللي في الـ repository. Magento بيستدعيهم ويحوّل النتيجة لـ JSON. أنت بس بتنادي الـ endpoint.

GET/rest/V1/tickets/5
response (JSON)json
{
  "entity_id": 5,
  "title": "Login issue",
  "status": "open"
}
الـ list مع فلاتر

الـ getList بيدعم فلاتر متقدمة عن طريق الـ searchCriteria في الـ query string — Magento بيبنيها أوتوماتيك.

GET/rest/V1/tickets?searchCriteria[filter_groups][0][filters][0][field]=status&...[value]=open
i
الـ searchCriteria شكله معقّد بس قوي جدًا: بيدعم filters, sorting, pagination كلها من الـ URL بدون أي كود إضافي منك.
• • •
05

Create — POST

إنشاء ticket. بتبعت الـ data في الـ body، وMagento بيحوّلها لـ object ويناديها بالـ save.

إزاي بيشتغل

بتبعت JSON فيه مفتاح ticket (باسم الـ parameter في method الـ save). Magento بيحوّله لـ TicketInterface object ويمرّره للـ save أوتوماتيك.

POST/rest/V1/tickets
request body (JSON)json
{
  "ticket": {
    "title": "Payment failed",
    "status": "open"
  }
}
response (JSON)json
{
  "entity_id": 6,
  "title": "Payment failed",
  "status": "open"
}
i
اسم المفتاح في الـ JSON ("ticket") لازم يطابق اسم الـ parameter في الـ method: save(TicketInterface $ticket). ده اللي بيربط الـ JSON بالـ object.
• • •
06

Update — PUT

التعديل بيستخدم نفس method الـ save، بس مع id في الـ URL.

ليه نفس الـ save

الـ save بتعمل الاتنين: لو الـ object مالوش id بتعمل create، ولو ليه id بتعمل update. في الـ PUT، الـ id بييجي من الـ URL فبتعرف تحدّث الموجود.

PUT/rest/V1/tickets/6
request body (JSON)json
{
  "ticket": {
    "status": "closed"
  }
}
!
لازم الـ repository بتاعك يتعامل مع دمج الـ id من الـ URL مع الـ data من الـ body. عادةً بتجيب الموجود بالـ id الأول، تعدّل عليه، وبعدين تحفظ — عشان متمسحش الحقول اللي مبعتش.
• • •
07

Delete — DELETE

الأبسط. الـ id في الـ URL، ومربوط بـ deleteById.

إزاي بيشتغل

الـ route مربوط بـ deleteById اللي بياخد int $id. الـ id بييجي من الـ URL مباشرة. بيرجّع true لو نجح.

DELETE/rest/V1/tickets/6
responsejson
true
i
عشان كده عرّفنا deleteById في الـ repository — لأن الـ DELETE endpoint بيبعت id بس، مش object كامل. ده أنظف من إنك تبعت object في الـ body مع DELETE.
• • •
08

الاختبار والأخطاء

التفعيل، الـ authentication، وأشهر المشاكل.

أغلب الـ endpoints محتاجة token. أول حاجة بتجيب token، وبعدين بتبعته في كل request.

get admin tokenbash
POST /rest/V1/integration/admin/token
# body:
{ "username": "admin", "password": "..." }

# returns a token string, then send it:
Authorization: Bearer <token>
i
فيه أنواع tokens: admin (للـ backend)، customer (لعميل مسجّل)، وintegration (لتطبيق خارجي). كل واحد بيوصل للـ resources اللي مصرّح له بيها في الـ ACL.
terminalbash
php bin/magento setup:upgrade
php bin/magento cache:clean
php bin/magento setup:di:compile
  • جرّب بـ Postman أو curl أو Insomnia.
  • Magento بيولّد Swagger docs أوتوماتيك على /swagger — بتلاقي فيه كل الـ endpoints.
  • لأي عملية كتابة، متنساش الـ Authorization header.
  • 404 على الـ endpoint: نسيت setup:upgrade أو الـ URL في webapi.xml غلط.
  • 401 Unauthorized: مبعتش token، أو الـ token انتهى.
  • 403 Forbidden: الـ token مالوش الصلاحية المطلوبة في الـ <resources>.
  • الـ POST بيرجّع null أو error: اسم المفتاح في الـ JSON مش مطابق لاسم الـ parameter في الـ method.
  • الـ serialization غلط: الـ Data interface types ناقصة أو غلط.
ASKالفرق الجوهري بين REST و GraphQL في Magento؟
الإجابة: REST بيتعرّف بالكامل بـ webapi.xml (مفيش كود resolver) وبيرجّع structure ثابت لكل endpoint. GraphQL محتاج resolver لكل عملية، بس بيدّي الـ client حرية يطلب الحقول اللي عايزها بالظبط في request واحد. الاتنين بيعتمدوا على نفس الـ repository.

REST API CRUD كامل ✓

دلوقتي عندك REST API كامل: Read, Create, Update, Delete — كله مبني على service contracts، وأغلبه مجرد config في webapi.xml بدون كود resolver.

الخلاصة الذهبية: repository قوي = REST + GraphQL شبه مجانيين. اصرف مجهودك في الـ service contract، والـ APIs بتتبني فوقه بسهولة.

// magento 2 backend · rest api full crud · hands-on

خلّصت الدرس؟علّمه عشان تتابع تقدّمك في الكورس.

كاتب الدرس

Abdulrahman Masoud

عندك سؤال على الدرس أو محتاج مساعدة في مشروع Magento؟ كلّمني.

أسئلة شائعة

إزاي أعمل REST API لـ custom entity في Magento 2؟

بتعرّف service contract الأول: Data interface لشكل البيانات وRepository interface فيه save وgetById وgetList وdeleteById. بعدها بتربط كل URL وHTTP verb بـ method في الـ repository جوّه etc/webapi.xml، وبتعرّف الصلاحيات في acl.xml. Magento بيتولّى الـ routing وتحويل الـ JSON والـ authorization، فمش محتاج تكتب controllers.

إيه وظيفة ملف webapi.xml في Magento 2؟

ده الملف اللي بيربط كل endpoint بالكود: كل route فيه الـ url والـ HTTP method، وعنصر service بيحدد الـ interface والـ method اللي هتتنادى، وعنصر resources بيحدد الصلاحية المطلوبة. ولو الـ repository جاهز، الـ REST API كله تقريبًا بيبقى config في الملف ده من غير كود resolver.

إزاي أعمل Create و Update لنفس الـ entity في Magento 2 REST API؟

الاتنين بيتربطوا بنفس method الـ save: الـ POST على /V1/tickets بيعمل create، والـ PUT على /V1/tickets/:id بيعمل update لأن الـ id جاي من الـ URL. البيانات بتتبعت في الـ body تحت مفتاح اسمه نفس اسم الـ parameter، زي ticket لـ save(TicketInterface $ticket). وفي الـ update الأحسن الـ repository يجيب الـ record الموجود بالـ id ويعدّل عليه قبل الحفظ عشان متمسحش الحقول اللي مبعتتهاش.

ليه أعمل deleteById في الـ repository مع إن فيه delete؟

الـ delete بياخد object كامل وده مفيد جوّه الكود، لكن الـ DELETE endpoint بيبعت الـ id في الـ URL بس. عشان كده بتربط الـ route بـ deleteById(int $id)، والـ :id في الـ URL بيتطابق مع الـ parameter اللي اسمه $id، وبيرجّع true لو الحذف نجح.

يعني إيه resource ref="anonymous" في webapi.xml؟

لما تحط ref="anonymous" بدل ACL resource، الـ endpoint بيبقى public وأي حد يقدر يوصله من غير token. استخدمه بحذر شديد وللبيانات العامة بس، وأي عملية كتابة اربطها بصلاحية معرّفة في acl.xml.

إزاي أعمل filter و pagination لـ getList في Magento 2 REST API؟

الـ GET list endpoint بيقبل searchCriteria في الـ query string، زي searchCriteria[filter_groups][0][filters][0][field]=status. شكله معقّد شوية بس بيدعم الـ filters والـ sorting والـ pagination كلها من الـ URL، وMagento بيبني الـ SearchCriteria أوتوماتيك من غير أي كود إضافي منك.

ما الفرق بين REST و GraphQL في Magento 2؟

الـ REST بيتعرّف بالكامل في webapi.xml من غير كود resolver، وكل endpoint بيرجّع structure ثابت. الـ GraphQL محتاج resolver لكل عملية، بس بيدّي الـ client حرية يطلب الحقول اللي عايزها بالظبط في request واحد. والاتنين بيعتمدوا على نفس الـ repository، فالـ service contract القوي بيخلّي الاتنين سهلين.