API Platform Symfony REST: Hướng Dẫn Đầy Đủ và Câu Hỏi Phỏng Vấn 2026

Hướng dẫn chi tiết API Platform Symfony để xây dựng REST API hiện đại. Tìm hiểu cách cài đặt, cấu hình, thao tác CRUD và các câu hỏi phỏng vấn 2026.

API Platform Symfony REST: Hướng Dẫn Đầy Đủ và Câu Hỏi Phỏng Vấn 2026

API Platform là framework PHP phổ biến nhất để xây dựng API hiện đại dựa trên Symfony. Framework này cung cấp nhiều tính năng sẵn có như tài liệu OpenAPI, phân trang, lọc dữ liệu và xác thực. Bài viết này hướng dẫn cách sử dụng API Platform để xây dựng REST API có khả năng mở rộng và sẵn sàng cho production.

API Platform 4.x giới thiệu state providers và processors mới thay thế data providers cũ. Hãy đảm bảo sử dụng phiên bản mới nhất để có được tất cả các tính năng hiện đại.

Cài Đặt API Platform trong Symfony

Bước đầu tiên là cài đặt API Platform bằng Composer. Framework này tích hợp hoàn hảo với Symfony 7 và cung cấp bundle sẵn sàng sử dụng.

bash
composer create-project symfony/skeleton my-api
cd my-api
composer require api

Sau khi cài đặt, API Platform tự động cấu hình routes và tài liệu. Cấu hình cơ bản có thể được tìm thấy trong file config/packages/api_platform.yaml.

yaml
# config/packages/api_platform.yaml
api_platform:
    title: 'My API'
    version: '1.0.0'
    formats:
        jsonld: ['application/ld+json']
        json: ['application/json']
    defaults:
        stateless: true
        cache_headers:
            vary: ['Content-Type', 'Authorization', 'Origin']
    swagger:
        versions: [3]

Tạo Resource API Đầu Tiên

API Platform sử dụng PHP attributes để định nghĩa resources. Mỗi entity được đánh dấu với #[ApiResource] tự động có các endpoints CRUD.

php
<?php

namespace App\Entity;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use ApiPlatform\Metadata\Delete;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

#[ORM\Entity]
#[ApiResource(
    operations: [
        new GetCollection(),
        new Get(),
        new Post(),
        new Put(),
        new Delete()
    ],
    paginationItemsPerPage: 20
)]
class Product
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    #[Assert\NotBlank]
    #[Assert\Length(min: 3, max: 255)]
    private string $name;

    #[ORM\Column(type: 'text')]
    private string $description;

    #[ORM\Column(type: 'decimal', precision: 10, scale: 2)]
    #[Assert\Positive]
    private string $price;

    #[ORM\Column]
    private \DateTimeImmutable $createdAt;

    public function __construct()
    {
        $this->createdAt = new \DateTimeImmutable();
    }

    // Getters and setters...
}

Lọc và Sắp Xếp Dữ Liệu

API Platform cung cấp nhiều bộ lọc tích hợp có thể kích hoạt dễ dàng. Bộ lọc cho phép client truy vấn dữ liệu dựa trên các tiêu chí nhất định.

php
<?php

namespace App\Entity;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Doctrine\Orm\Filter\RangeFilter;
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[ApiResource]
#[ApiFilter(SearchFilter::class, properties: [
    'name' => 'partial',
    'description' => 'partial',
    'category.name' => 'exact'
])]
#[ApiFilter(OrderFilter::class, properties: ['name', 'price', 'createdAt'])]
#[ApiFilter(RangeFilter::class, properties: ['price'])]
#[ApiFilter(DateFilter::class, properties: ['createdAt'])]
class Product
{
    // Properties...
}

Ví dụ truy vấn sử dụng bộ lọc:

bash
# Tìm sản phẩm có tên chứa "laptop"
GET /api/products?name=laptop

# Lọc theo khoảng giá
GET /api/products?price[gte]=100&price[lte]=500

# Sắp xếp theo giá giảm dần
GET /api/products?order[price]=desc

Xác Thực và Serialization Groups

Xác thực trong API Platform sử dụng Symfony Validator component. Serialization groups cho phép kiểm soát chi tiết dữ liệu được trả về.

php
<?php

namespace App\Entity;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;

#[ORM\Entity]
#[ApiResource(
    normalizationContext: ['groups' => ['product:read']],
    denormalizationContext: ['groups' => ['product:write']],
    operations: [
        new GetCollection(normalizationContext: ['groups' => ['product:list']]),
        new Get(normalizationContext: ['groups' => ['product:read', 'product:detail']]),
        new Post()
    ]
)]
class Product
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    #[Groups(['product:read', 'product:list'])]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    #[Assert\NotBlank(message: 'Product name is required')]
    #[Groups(['product:read', 'product:list', 'product:write'])]
    private string $name;

    #[ORM\Column(type: 'text')]
    #[Groups(['product:read', 'product:detail', 'product:write'])]
    private string $description;

    #[ORM\Column(type: 'decimal', precision: 10, scale: 2)]
    #[Assert\Positive(message: 'Price must be positive')]
    #[Groups(['product:read', 'product:list', 'product:write'])]
    private string $price;

    // Getters and setters...
}

State Providers và Processors

API Platform 4 giới thiệu State Providers và Processors cho custom logic. Đây là sự thay thế cho Data Providers và Data Persisters từ phiên bản trước.

php
<?php

namespace App\State;

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\Repository\ProductRepository;

class ProductStateProvider implements ProviderInterface
{
    public function __construct(
        private ProductRepository $repository
    ) {}

    public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
    {
        if (isset($uriVariables['id'])) {
            return $this->repository->find($uriVariables['id']);
        }

        return $this->repository->findActiveProducts();
    }
}

State Processor cho custom logic khi lưu dữ liệu:

php
<?php

namespace App\State;

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Mailer\MailerInterface;

class ProductProcessor implements ProcessorInterface
{
    public function __construct(
        private EntityManagerInterface $em,
        private MailerInterface $mailer
    ) {}

    public function process(
        mixed $data,
        Operation $operation,
        array $uriVariables = [],
        array $context = []
    ): mixed {
        $this->em->persist($data);
        $this->em->flush();

        // Send notification email
        $this->sendNotification($data);

        return $data;
    }

    private function sendNotification(object $product): void
    {
        // Email logic...
    }
}

Xác Thực và Phân Quyền

API Platform tích hợp với Symfony Security cho xác thực JWT hoặc API token.

yaml
# config/packages/security.yaml
security:
    firewalls:
        api:
            pattern: ^/api
            stateless: true
            jwt: ~

    access_control:
        - { path: ^/api/docs, roles: PUBLIC_ACCESS }
        - { path: ^/api/products, roles: PUBLIC_ACCESS, methods: [GET] }
        - { path: ^/api, roles: ROLE_USER }

Sử dụng security ở cấp resource:

php
<?php

namespace App\Entity;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Delete;

#[ApiResource(
    operations: [
        new Get(),
        new Post(security: "is_granted('ROLE_ADMIN')"),
        new Delete(
            security: "is_granted('ROLE_ADMIN') or object.owner == user",
            securityMessage: "Only admin or owner can delete this resource"
        )
    ]
)]
class Product
{
    // Properties...
}

Kiểm Thử API Endpoints

Kiểm thử API rất quan trọng để đảm bảo các endpoints hoạt động chính xác. Symfony cung cấp WebTestCase cho functional testing.

php
<?php

namespace App\Tests\Api;

use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
use App\Entity\Product;
use Doctrine\ORM\EntityManagerInterface;

class ProductApiTest extends ApiTestCase
{
    private EntityManagerInterface $em;

    protected function setUp(): void
    {
        $this->em = self::getContainer()->get('doctrine')->getManager();
    }

    public function testGetProducts(): void
    {
        $response = static::createClient()->request('GET', '/api/products');

        $this->assertResponseIsSuccessful();
        $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
        $this->assertJsonContains(['@type' => 'hydra:Collection']);
    }

    public function testCreateProduct(): void
    {
        $response = static::createClient()->request('POST', '/api/products', [
            'json' => [
                'name' => 'New Product',
                'description' => 'Product description',
                'price' => '99.99'
            ],
            'headers' => [
                'Authorization' => 'Bearer ' . $this->getToken()
            ]
        ]);

        $this->assertResponseStatusCodeSame(201);
        $this->assertJsonContains(['name' => 'New Product']);
    }

    public function testValidationError(): void
    {
        $response = static::createClient()->request('POST', '/api/products', [
            'json' => [
                'name' => '',
                'price' => -10
            ]
        ]);

        $this->assertResponseStatusCodeSame(422);
    }
}

Câu Hỏi Phỏng Vấn API Platform 2026

Dưới đây là các câu hỏi thường gặp trong phỏng vấn liên quan đến API Platform:

1. Sự khác biệt giữa State Provider và Data Provider là gì?

State Provider là cách tiếp cận mới trong API Platform 4 linh hoạt hơn. Data Provider đã deprecated và được thay thế bởi State Provider hỗ trợ async operations và type safety tốt hơn.

2. Làm thế nào để triển khai pagination tùy chỉnh?

Pagination có thể được tùy chỉnh thông qua cấu hình resource hoặc bằng cách tạo custom Paginator triển khai PaginatorInterface.

3. Giải thích sự khác biệt giữa normalization và denormalization context?

Normalization context được sử dụng khi dữ liệu được chuyển đổi từ object sang array/JSON (response). Denormalization context được sử dụng khi dữ liệu được chuyển đổi từ JSON sang object (request).

4. Làm thế nào để xử lý quan hệ trong API Platform?

Quan hệ có thể được expose dưới dạng IRI (tham chiếu) hoặc embedded object sử dụng serialization groups. Đối với thao tác lồng nhau, sử dụng subresource hoặc custom operations.

5. OpenAPI là gì và API Platform sử dụng nó như thế nào?

OpenAPI (trước đây là Swagger) là đặc tả cho tài liệu API. API Platform tự động tạo tài liệu OpenAPI dựa trên metadata của resources.

Sẵn sàng chinh phục phỏng vấn Symfony?

Luyện tập với mô phỏng tương tác, flashcards và bài kiểm tra kỹ thuật.

Kết Luận

API Platform cung cấp giải pháp toàn diện để xây dựng REST API với Symfony. Với các tính năng như thao tác CRUD tự động, lọc, phân trang và tài liệu OpenAPI, developer có thể tập trung vào business logic mà không cần viết boilerplate code. Hiểu biết sâu sắc về State Providers, Processors và serialization groups rất quan trọng để tận dụng tối đa API Platform trong các dự án production.

Thử thách hôm nay

Bạn có tìm ra lỗi trong Symfony không?

Một đoạn mã thật, một lỗi ẩn, mỗi ngày một lượt. Không cần tài khoản để thử.

Anthony Fillion-Maillet

Viết bởi

Anthony Fillion-Maillet

Người sáng lập SharpSkill

Lập trình viên fullstack hơn 10 năm. Anh điều hành SharpSkill và chịu trách nhiệm về mọi nội dung đăng tại đây.

Cập nhật ngày 25 tháng 8, 2026

Chia sẻ

Bài viết liên quan