PHP API разработка: Laravel API vs Symfony API

← Вернуться к статьям

Введение

PHP остается одним из самых популярных языков для веб-разработки, и два фреймворка доминируют в экосистеме: Laravel и Symfony. Оба отлично подходят для создания REST API, но имеют разные подходы и философии разработки.

В этой статье мы сравним Laravel API Resources и Symfony API Platform — два популярных подхода к разработке API на PHP. Рассмотрим их особенности, производительность, интеграцию с OpenAPI и когда какой фреймворк использовать.

✅ Что вы узнаете:

📋 Содержание

1. Laravel API Resources 🚀

Laravel предоставляет элегантный способ преобразования моделей и их коллекций в JSON через API Resources. Это позволяет контролировать формат ответа и легко добавлять метаданные.

Установка и настройка

# Создание нового Laravel проекта
composer create-project laravel/laravel api-project

# Установка Laravel Sanctum для аутентификации
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate

Создание API Resource

<?php

// app/Http/Resources/UserResource.php
namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
            'created_at' => $this->created_at->toIso8601String(),
            'updated_at' => $this->updated_at->toIso8601String(),
        ];
    }

    // Дополнительные данные для ответа
    public function with($request)
    {
        return [
            'meta' => [
                'version' => '1.0',
                'timestamp' => now()->toIso8601String(),
            ],
        ];
    }
}

Использование в контроллере

<?php

// app/Http/Controllers/UserController.php
namespace App\Http\Controllers;

use App\Http\Resources\UserResource;
use App\Models\User;
use Illuminate\Http\Request;

class UserController extends Controller
{
    public function index()
    {
        $users = User::paginate(15);
        return UserResource::collection($users);
    }

    public function show($id)
    {
        $user = User::findOrFail($id);
        return new UserResource($user);
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'email' => 'required|email|unique:users',
            'password' => 'required|min:8',
        ]);

        $user = User::create($validated);
        return new UserResource($user);
    }

    public function update(Request $request, $id)
    {
        $user = User::findOrFail($id);
        
        $validated = $request->validate([
            'name' => 'sometimes|string|max:255',
            'email' => 'sometimes|email|unique:users,email,' . $id,
        ]);

        $user->update($validated);
        return new UserResource($user);
    }

    public function destroy($id)
    {
        $user = User::findOrFail($id);
        $user->delete();
        
        return response()->json(null, 204);
    }
}

Роутинг для API

<?php

// routes/api.php
use App\Http\Controllers\UserController;
use Illuminate\Support\Facades\Route;

Route::middleware('auth:sanctum')->group(function () {
    Route::apiResource('users', UserController::class);
});

// Без аутентификации
Route::get('/users', [UserController::class, 'index']);
Route::get('/users/{id}', [UserController::class, 'show']);

Условные поля в Resource

<?php

// Условное включение полей
class UserResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->when(
                $request->user() && $request->user()->isAdmin(),
                $this->email
            ),
            'profile' => new ProfileResource($this->whenLoaded('profile')),
            'posts' => PostResource::collection($this->whenLoaded('posts')),
        ];
    }
}
✅ Преимущества Laravel API:
❌ Недостатки Laravel API:

2. Symfony API Platform 🏛️

API Platform — это полнофункциональный фреймворк для создания REST и GraphQL API на базе Symfony. Он автоматически генерирует документацию, CRUD операции и множество других функций из аннотаций или атрибутов.

Установка и настройка

# Создание нового Symfony проекта
composer create-project symfony/skeleton api-project
cd api-project

# Установка API Platform
composer require api

# Установка Doctrine ORM
composer require doctrine orm symfony/orm-pack

Создание Entity с API Platform

<?php

// src/Entity/User.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;

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

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

    #[ORM\Column(length: 255, unique: true)]
    #[Assert\NotBlank]
    #[Assert\Email]
    private ?string $email = null;

    #[ORM\Column]
    private ?\DateTimeImmutable $createdAt = null;

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

    // Getters и Setters
    public function getId(): ?int
    {
        return $this->id;
    }

    public function getName(): ?string
    {
        return $this->name;
    }

    public function setName(string $name): self
    {
        $this->name = $name;
        return $this;
    }

    public function getEmail(): ?string
    {
        return $this->email;
    }

    public function setEmail(string $email): self
    {
        $this->email = $email;
        return $this;
    }

    public function getCreatedAt(): ?\DateTimeImmutable
    {
        return $this->createdAt;
    }
}

Кастомизация сериализации

<?php

// src/Serializer/UserNormalizer.php
namespace App\Serializer;

use App\Entity\User;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;

class UserNormalizer implements NormalizerInterface
{
    public function __construct(
        private ObjectNormalizer $normalizer
    ) {
    }

    public function normalize($object, string $format = null, array $context = [])
    {
        $data = $this->normalizer->normalize($object, $format, $context);
        
        // Кастомизация данных
        $data['created_at'] = $object->getCreatedAt()->format('Y-m-d\TH:i:s\Z');
        
        return $data;
    }

    public function supportsNormalization($data, string $format = null): bool
    {
        return $data instanceof User;
    }
}

Фильтрация и пагинация

<?php

#[ApiResource(
    operations: [
        new GetCollection(
            filters: ['user.name', 'user.email'],
            paginationEnabled: true,
            paginationItemsPerPage: 15
        )
    ]
)]
#[ORM\Entity]
#[ApiFilter(SearchFilter::class, properties: [
    'name' => 'partial',
    'email' => 'exact'
])]
class User
{
    // ...
}
✅ Преимущества Symfony API Platform:
❌ Недостатки Symfony API Platform:

3. Сравнение фреймворков 📊

Критерий Laravel API Symfony API Platform
Скорость разработки ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐
Простота изучения ⭐⭐⭐⭐⭐ ⭐⭐⭐
Автоматизация ⭐⭐⭐ ⭐⭐⭐⭐⭐
Гибкость ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
Документация API Требует настройки Автоматическая (OpenAPI)
GraphQL поддержка Через пакеты Встроенная
Фильтрация/Сортировка Ручная реализация Автоматическая
Производительность ⭐⭐⭐⭐ ⭐⭐⭐⭐

4. OpenAPI интеграция 📘

Laravel + OpenAPI

# Установка DarkaOnLine/L5-Swagger
composer require darkaonline/l5-swagger
php artisan vendor:publish --provider "L5Swagger\L5SwaggerServiceProvider"
<?php

/**
 * @OA\Get(
 *     path="/api/users",
 *     summary="Получить список пользователей",
 *     tags={"Users"},
 *     @OA\Response(
 *         response=200,
 *         description="Успешный ответ",
 *         @OA\JsonContent(
 *             type="array",
 *             @OA\Items(ref="#/components/schemas/User")
 *         )
 *     )
 * )
 */
public function index()
{
    return UserResource::collection(User::all());
}

/**
 * @OA\Schema(
 *     schema="User",
 *     type="object",
 *     title="User",
 *     properties={
 *         @OA\Property(property="id", type="integer", example=1),
 *         @OA\Property(property="name", type="string", example="John Doe"),
 *         @OA\Property(property="email", type="string", example="john@example.com")
 *     }
 * )
 */

Symfony API Platform + OpenAPI

API Platform автоматически генерирует OpenAPI документацию из аннотаций/атрибутов. Документация доступна по адресу /api/docs.

<?php

#[ApiResource(
    operations: [
        new Get(
            uriTemplate: '/users/{id}',
            openapiContext: [
                'summary' => 'Получить пользователя',
                'description' => 'Возвращает информацию о пользователе по ID'
            ]
        )
    ],
    openapiContext: [
        'tags' => ['Users'],
        'responses' => [
            '200' => [
                'description' => 'Успешный ответ',
                'content' => [
                    'application/json' => [
                        'schema' => [
                            '$ref' => '#/components/schemas/User'
                        ]
                    ]
                ]
            ]
        ]
    ]
)]
class User
{
    // ...
}

5. Производительность 🚀

Оба фреймворка показывают хорошую производительность. Laravel обычно немного быстрее для простых операций, но API Platform может быть эффективнее для сложных запросов благодаря оптимизациям Doctrine.

Операция Laravel API Symfony API Platform
GET /users (список) ~2,500 req/s ~2,200 req/s
GET /users/{id} ~3,000 req/s ~2,800 req/s
POST /users ~2,000 req/s ~1,900 req/s
Сложные запросы с фильтрами ~1,800 req/s ~2,000 req/s

💡 Примечание о производительности:

Бенчмарки показывают примерные значения. Реальная производительность зависит от сложности бизнес-логики, работы с базой данных и конфигурации сервера. Оба фреймворка достаточно производительны для большинства приложений.

6. Когда что использовать 🎯

Используйте Laravel API, если:

Используйте Symfony API Platform, если:

Заключение

Оба фреймворка отлично подходят для разработки API на PHP. Laravel лучше для быстрой разработки и простых проектов, а Symfony API Platform — для сложных enterprise решений с автоматизацией и максимальной гибкостью.

💡 Рекомендации:

⚠️ Важно помнить:

Создайте Mock API за 2 минуты

Используйте Mock API для тестирования интеграции с PHP API без необходимости настраивать реальный backend. LightBox API позволяет быстро создать тестовые endpoints для разработки и тестирования.

Попробовать бесплатно →
← Вернуться к статьям