خطوة 26: عرض API مع منصة (API Platform)

5.0 version
Maintained

عرض API مع منصة (API Platform)

لقد انتهينا من تنفيذ موقع سجل الزوار. للسماح بمزيد من استخدام البيانات ، ماذا عن كشف API الآن؟ يمكن استخدام واجهة برمجة التطبيقات (API) بواسطة تطبيق جوال لعرض جميع المؤتمرات ، وتعليقاتهم ، وربما السماح للحاضرين بإرسال التعليقات.

في هذه الخطوة ، سنقوم بتنفيذ API للقراءة فقط.

تثبيت منصة API

من الممكن تعريض واجهة برمجة التطبيقات عن طريق كتابة بعض الأكواد ، ولكن إذا أردنا استخدام المعايير ، فمن الأفضل أن نستخدم حلاً يعتني بالفعل بالتحميل الثقيل. حل مثل API المنصة:

1
$ symfony composer req api

تعريض API للمؤتمرات

بعض التعليقات التوضيحية على فئة المؤتمر هي كل ما نحتاج إليه لتكوين API

patch_file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
--- a/src/Entity/Conference.php
+++ b/src/Entity/Conference.php
@@ -2,15 +2,24 @@

 namespace App\Entity;

+use ApiPlatform\Core\Annotation\ApiResource;
 use App\Repository\ConferenceRepository;
 use Doctrine\Common\Collections\ArrayCollection;
 use Doctrine\Common\Collections\Collection;
 use Doctrine\ORM\Mapping as ORM;
 use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
+use Symfony\Component\Serializer\Annotation\Groups;
 use Symfony\Component\String\Slugger\SluggerInterface;

 /**
  * @ORM\Entity(repositoryClass=ConferenceRepository::class)
  * @UniqueEntity("slug")
+ *
+ * @ApiResource(
+ *     collectionOperations={"get"={"normalization_context"={"groups"="conference:list"}}},
+ *     itemOperations={"get"={"normalization_context"={"groups"="conference:item"}}},
+ *     order={"year"="DESC", "city"="ASC"},
+ *     paginationEnabled=false
+ * )
  */
 class Conference
 {
@@ -18,21 +26,29 @@ class Conference
      * @ORM\Id()
      * @ORM\GeneratedValue()
      * @ORM\Column(type="integer")
+     *
+     * @Groups({"conference:list", "conference:item"})
      */
     private $id;

     /**
      * @ORM\Column(type="string", length=255)
+     *
+     * @Groups({"conference:list", "conference:item"})
      */
     private $city;

     /**
      * @ORM\Column(type="string", length=4)
+     *
+     * @Groups({"conference:list", "conference:item"})
      */
     private $year;

     /**
      * @ORM\Column(type="boolean")
+     *
+     * @Groups({"conference:list", "conference:item"})
      */
     private $isInternational;

@@ -43,6 +59,8 @@ class Conference

     /**
      * @ORM\Column(type="string", length=255, unique=true)
+     *
+     * @Groups({"conference:list", "conference:item"})
      */
     private $slug;

يقوم الشرح الرئيسي `` @ ApiResource`` بتكوين واجهة برمجة التطبيقات للمؤتمرات. يقيد العمليات المحتملة `` get``وتكوين أشياء مختلفة: مثل الحقول التي سيتم عرضها وكيفية ترتيب المؤتمرات.

بشكل افتراضي ، نقطة الدخول الرئيسية لواجهة برمجة التطبيقات هي /api بفضل التكوين من``config/routes/api_platform.yaml`` التي تمت إضافتها بواسطة وصفة الحزمة.

تسمح لك واجهة الويب بالتفاعل مع واجهة برمجة التطبيقات:

استخدمها لاختبار الاحتمالات المختلفة:

تخيل الوقت الذي يستغرقه تنفيذ كل هذا من الصفر!

تعريض API للتعليقات

افعل نفس الشيء للتعليقات:

patch_file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
--- a/src/Entity/Comment.php
+++ b/src/Entity/Comment.php
@@ -2,12 +2,25 @@

 namespace App\Entity;

+use ApiPlatform\Core\Annotation\ApiFilter;
+use ApiPlatform\Core\Annotation\ApiResource;
+use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
 use App\Repository\CommentRepository;
 use Doctrine\ORM\Mapping as ORM;
+use Symfony\Component\Serializer\Annotation\Groups;
 use Symfony\Component\Validator\Constraints as Assert;

 /**
  * @ORM\Entity(repositoryClass=CommentRepository::class)
  * @ORM\HasLifecycleCallbacks()
+ *
+ * @ApiResource(
+ *     collectionOperations={"get"={"normalization_context"={"groups"="comment:list"}}},
+ *     itemOperations={"get"={"normalization_context"={"groups"="comment:item"}}},
+ *     order={"createdAt"="DESC"},
+ *     paginationEnabled=false
+ * )
+ *
+ * @ApiFilter(SearchFilter::class, properties={"conference": "exact"})
  */
 class Comment
 {
@@ -15,18 +27,24 @@ class Comment
      * @ORM\Id()
      * @ORM\GeneratedValue()
      * @ORM\Column(type="integer")
+     *
+     * @Groups({"comment:list", "comment:item"})
      */
     private $id;

     /**
      * @ORM\Column(type="string", length=255)
      * @Assert\NotBlank
+     *
+     * @Groups({"comment:list", "comment:item"})
      */
     private $author;

     /**
      * @ORM\Column(type="text")
      * @Assert\NotBlank
+     *
+     * @Groups({"comment:list", "comment:item"})
      */
     private $text;

@@ -34,22 +52,30 @@ class Comment
      * @ORM\Column(type="string", length=255)
      * @Assert\NotBlank
      * @Assert\Email
+     *
+     * @Groups({"comment:list", "comment:item"})
      */
     private $email;

     /**
      * @ORM\Column(type="datetime")
+     *
+     * @Groups({"comment:list", "comment:item"})
      */
     private $createdAt;

     /**
      * @ORM\ManyToOne(targetEntity=Conference::class, inversedBy="comments")
      * @ORM\JoinColumn(nullable=false)
+     *
+     * @Groups({"comment:list", "comment:item"})
      */
     private $conference;

     /**
      * @ORM\Column(type="string", length=255, nullable=true)
+     *
+     * @Groups({"comment:list", "comment:item"})
      */
     private $photoFilename;

يتم استخدام نفس النوع من التعليقات التوضيحية لتكوين الفصل.

تقييد التعليقات المكشوفة بواسطة API

بشكل افتراضي ، يكشف منصة API كل الإدخالات من قاعدة البيانات. ولكن بالنسبة للتعليقات ، يجب أن تكون التعليقات المنشورة فقط جزءًا من واجهة برمجة التطبيقات.

عندما تحتاج إلى تقييد العناصر التي يتم إرجاعها بواسطة API ، قم بإنشاء خدمة تنفذ QueryCollectionExtensionInterface للتحكم في استعلام Doctrine المستخدم في المجموعات و / أو QueryItemExtensionInterface للتحكم في العناصر:

src/Api/FilterPublishedCommentQueryExtension.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
namespace App\Api;

use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryItemExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use App\Entity\Comment;
use Doctrine\ORM\QueryBuilder;

class FilterPublishedCommentQueryExtension implements QueryCollectionExtensionInterface, QueryItemExtensionInterface
{
    public function applyToCollection(QueryBuilder $qb, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null)
    {
        if (Comment::class === $resourceClass) {
            $qb->andWhere(sprintf("%s.state = 'published'", $qb->getRootAliases()[0]));
        }
    }

    public function applyToItem(QueryBuilder $qb, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, string $operationName = null, array $context = [])
    {
        if (Comment::class === $resourceClass) {
            $qb->andWhere(sprintf("%s.state = 'published'", $qb->getRootAliases()[0]));
        }
    }
}

تطبق فئة ملحق الاستعلام المنطق الخاص بها فقط لمورد Comment وتعديل أداة إنشاء استعلام العقيدة للنظر في التعليقات في حالة published فقط.

تكوين CORS

تبعًا للإعدادات الافتراضية ، فإن سياسة الأمان ذات الأصل الأصلي لعملاء HTTP الحديث تجعل استدعاء API من مجال آخر محظور. حزمة CORS ، المثبتة كجزء من composer req api، يرسل رؤوس مشاركة المصادر المشتركة استنادًا إلى متغير البيئة `` CORS_ALLOW_ORIGIN``

تبعًا للإعدادات الافتراضية ، تسمح قيمته ، المعرّفة في `` .env`` ، بطلبات HTTP من localhost و``127.0.0.1`` على أي منفذ. هذا هو بالضبط ما نحتاجه للخطوة التالية حيث سنقوم بإنشاء SPA التي سيكون لها خادم الويب الخاص بها والذي سيتصل بـ API.


  • « Previous خطوة 25: إشعار من قبل جميع وسائل
  • Next » خطوة 27: بناء SPA

This work, including the code samples, is licensed under a Creative Commons BY-NC-SA 4.0 license.