Вы узнаете, что такое Ресурсы и как их использовать для API в Laravel-приложениях.
Ресурсы (Resources) — дополнительный слой поверх Eloquent-моделей. Они позволяют поддерживать единый формат возвращаемых данных. Плюс позволяют отсекать лишние или секретные данные, например, пароли и токены.
Настройка проекта
Создадим новый Laravel-проект с пользователями. Откроем миграцию database/migrations/2014_10_12_000000_create_users_table.php
и добавим в Schema::create
новое поле с возрастом:
$table->integer('age');
Откроем фабрику database/factories/UserFactory.php
и также добавим в него поле возраста:
public function definition() { return [ 'name' => $this->faker->name(), 'email' => $this->faker->unique()->safeEmail(), 'email_verified_at' => now(), 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'remember_token' => Str::random(10), 'age' => $this->faker->numberBetween(10, 90) ]; }
Откроем пользовательскую модель app/Models/User.php
и добавим возраст в массив $fillable
:
protected $fillable = [ 'name', 'email', 'password', 'age' ];
Выполним миграции:
php artisan migrate
База данных готова. Займемся её наполнением. Открываем database/seeders/DatabaseSeeder.php
и раскомментируем (убираем два слэша в начале) следующую строку:
// \App\Models\User::factory(10)->create();
Выполняем посев (наполнение данными):
php artisan db:seed
Получаем 10 фейковых пользователей.
Создание Ресурса
Ресурсы создаются поверх eloquent-моделей. То есть для каждой модели вам нужен отдельный ресурс.
Создадим Ресурс для модели User
и посмотрим как его можно использовать для запросов.
Ресурс создается следующей artisan-командой:
php artisan make:resource UserResource
Она создаст новый класс UserResource
в папке app/Http/Resources
. В этой папке будут находится все создаваемые Ресурсы.
Открываем файл UserResource
и видим в нём метод toArray
. Он используется для возврата данных пользователя. По умолчанию просто возвращается результат этого метода.
Текущая модель, для которой используется Ресурс, представлена внутри класса полем resource
. Соответственно, вы можете ссылаться на неё с помощью $this->resource
.
Изменим возвращаемый массив, чтобы он возвращал только идентификатор, имя и почту пользователя. Заменим содержимое метода toArray
на следующее:
return [ 'id' => $this->resource->id, 'name' => $this->resource->name, 'email' => $this->resource->email ];
Готово, мы создали наш первый Ресурс!
Создаем конечную точку API
Создадим эндпоинт, который позволит получать данные любого пользователя по его идентификатору. Но сначала создадим контроллер:
php artisan make:controller UserController
Откроем свежесозданный app/Http/Controllers/UserController.php
и создадим в нём новый метод getUser
, который будет принимать идентификатор и возвращать данные пользователя.
public function getUser($id) { $user = User::query()->find($id); if (!$user) { return response()->json(['success' => false, 'message' => 'User does not exist']); } return response()->json(['success' => true, 'user' => new UserResource($user)]); }
Сначала он проверяет, существует ли пользователь с таким идентификатором. Если нет, то возвращаем json с ошибкой. Если существует, то возвращаем экземпляр UserResource
.
Обратите внимание, что для создания экземпляра Ресурса вам необходимо передать ему модель. Например так:
new UserResource($user)
Это все! Осталось добавить конечную точку в маршруты.
Открываем routes/api.php
и добавляем:
Route::get('/user/{id}', [UserController::class, 'getUser']);
Наш API готов. Пора его проверить.
Запускаем сервер:
php artisan serve
Для тестирования API удобнее использовать что-то вроде Postman или Thunder Client. Но пока нам нужен обычнй GET-запрос без авторизации, то просто откроем адрес в браузере: localhost:8000/api/user/1
Видим, что нам пришёл json с двумя ключами success
и user
. Обратите внимание что объект user
содержит только id
, name
и email
, то есть именно те поля, которые мы настроили в нашем Ресурсе
.
Вы можете попробовать менять идентификатор и увидите, что API придерживается единой структуры ответа для всех пользователей.
Ресурс коллекции пользователей
Ресурсы предназначены не только для экземпляров моделей. Вы можете создать ресурс коллекции, который принимает в качестве параметра коллекции экземпляров моделей и, при необходимости, изменяет её.
Чтобы создать Ресурс коллекции для модели User
выполним следующую команду:
php artisan make:resource UserCollection --collection
Будет создан файл app/Http/Resources/UserCollection.php
.
Обратите внимание, что для Ресурсов коллекций существует соглашение об именах <Model>Collection
, которое гарантирует, что коллекция связана с правильной моделью.
Итак, поскольку название модели — User
, то название Ресурса коллекции будет UserCollection
. Если хотите назвать коллекцию по другому, то можете указать класс ресурса, используя поле $collects
в классе коллекции.
public $collects = User::class;
Ресурсы коллекций аналогичны обычным Ресурсам. Также есть метод toArray
, который используется для задания структуры коллекций.
Изменим его содержание на следующее:
$count = $this->collection->count(); return [ 'count' => $count, 'data' => $this->collection ];
Обратите внимание, что $this->collection
вернет массив объектов со структурой, аналогичной заданной в UserResource
, для каждого пользователя в коллекции.
Создаем конечную точку API
Создадим эндпоинт, которая позволит нам получить всех пользователей. Добавим в UserController
следующий метод:
public function getUsers () { $users = User::query()->get(); return response()->json(['success' => true, 'users' => new UserCollection($users)]); }
Для создания экземпляр ресурса коллекции также необходимо передать коллекцию моделей в качестве параметра.
Добавим новый маршрут в routes/api.php
:
Route::get('/user', [UserController::class, 'getUsers']);
Давайте его проверим. Открываем адрес localhost:8000/api/user
в браузере. Он вернет два ключа success
и users
, который содержит массив всех пользователей и все они будут иметь структуру, заданную наши в UserResource
.
Это пример того, как заданный Ресурс гарантирует одинаковую структуру для всех запросов.
Условные поля
Иногда, в зависимости от условий, вам нужно будет добавить дополнительное поле в ответ. Для этого можно использовать метод when
.
Предположим, что нам нужно возвращать возраст пользователя, если ему больше 18 лет. Добавим следующую строку в возвращаемый массив toArray
в UserResource
:
'old' => $this->when($this->resource->age > 18, true)
Теперь, если пользователь старше 18 лет, то в ответ будет добавлено полей age
. Обратите внимание, что первый параметр это условие, а второй — ожидаемое значение.
Откроем адрес localhost:8000/api/user
в браузере. Теперь у взрослых пользователей будет поле возраста, а у детей — нет.
Обратите внимание, что в вашем случае результат будет другой, так как фабрика генерирует пользователей случайным образом.
Заключение
Ресурсы позволяют структурировать данные выдаваемых в запросах и гарантировать сокрытие небезопасных данных.
Вы можете также почитать о Ресурсах в документации Laravel.
Код из статьи доступен на Github.
Автор: Shahed Nasser
Перевод: Алексей Широков
Наш Телеграм-канал — следите за новостями о Laravel.