Сегодня я хотел бы затронуть тему валидации в бэкенде с помощью Laravel. Для меня это часть того, что делает этот фреймворк таким элегантным и беглым. Несмотря на то, что он позволяет вам проверять ваши входные данные, используя несколько подходов, он дает вам защитные рельсы, чтобы гарантировать, что это будет работать хорошо и останется организованным по мере роста вашего приложения.
Давайте перейдем к коду. Я создал начальный проект, который вы можете использовать, чтобы следовать за ним. Просто клонируйте репозиторий отсюда. Это простой CRUD-проект с Rest API для показа, хранения, обновления и удаления наблюдений за птицами из приложения. В настоящее время в нем нет никакой валидации. Все, что он получает от клиентов, он будет пытаться сохранить или обновить в базе данных, что может быть очень плохо, даже если у вас есть валидация в клиентском коде. Давайте начнем исправлять это с помощью Form Requests.
Запросы форм
Честно говоря, если у вас есть только пара правил, вам может не понадобиться запрос формы, вы можете просто проверить запрос внутри метода контроллера, например:
// app/Http/Controllers/BurdSightingController.php
public function create(Request $request)
{
$request->validate([
'common_name' => 'required|string|max:255',
]);
$sighting = BirdSighting::create($request->validated());
return response()->json($sighting, 201);
}
Но если вам нужен более чистый интерфейс с контроллером и специальное место, где происходит валидация, то вы можете создать FormRequest с помощью команды artisan:
php artisan make:request CreateBirdSightingRequest
Это создаст следующий файл:
// app/Http/Requests/CreateBirdSightingRequest.php
class CreateBirdSightingRequest extends FormRequest
{
public function authorize()
{
return false;
}
public function rules()
{
return [
//
];
}
}
Метод authorize
может быть использован для определения того, имеет ли текущий пользователь право на выполнение данной операции, поэтому вы можете, например, использовать Врата и Политики или даже более простые правила, например, если у пользователя есть определенное свойство. Убедитесь, что этот метод возвращает булево значение: true означает, что пользователь авторизован, а false означает, что пользователь не авторизован и ответит HTTP-статусом 403.
Метод rules
— это место, где находятся фактические правила валидации. В Laravel есть десятки встроенных правил валидации, которые можно добавить сюда. Итак, в нашем случае мы хотим проверить поля, чтобы создать наблюдение за птицами:
public function rules()
{
return [
'common_name' => 'required|string|max:255',
'species' => 'required|string|max:255',
'sighted_at' => 'required|date',
'quantity' => 'nullable|integer|min:1',
'latitude' => 'required|numeric',
'longitude' => ['required', 'numeric'],
];
}
Вы заметите, что для longitude
я использовал другой синтаксис. Laravel поддерживает как строки с правилами, разделенными |
, так и массивы с правилами, разделенными запятыми. Насколько я знаю, строковый синтаксис можно использовать только со встроенными правилами. Если вы создаете пользовательское правило валидации (и я покажу вам, как это сделать), то вам придется использовать синтаксис массива.
Пользовательские сообщения валидации
Form Requests также позволяет вам добавлять пользовательские сообщения валидации для каждого поля и правила. Для этого вам нужно переопределить метод messages
в созданном вами запросе формы, например:
public function messages()
{
return [
'common_name.required' => 'A common name for the bird you saw is required',
'sighted_at.required' => 'An approximate date and time for the sighting is required',
];
}
Эти сообщения переопределят стандартное сообщение валидации для правила required
, которое вы можете найти в resources/lang/validation.php
.
Наконец, вы должны использовать этот запрос формы в своем методе, поэтому вернитесь в контроллер и замените Request $request
на CreateBirdSightingRequest $request
.
public function create(CreateBirdSightingRequest $request)
{
$sighting = BirdSighting::create($request->validated());
return response()->json($sighting, 201);
}
Вы также заметите, что мы заменили $request->all()
на $request->validated()
для получения подтвержденных полей из запроса.
Теперь, если вы отправите данные в эту конечную точку, и они не будут соответствовать правилам, которые вы добавили, вы получите ответ со статусом 422 HTTP с сообщениями об ошибках для каждого поля.
Организация правил
Теперь вам понадобится другой запрос формы для метода update
, который может иметь другой набор правил, и, говоря о наборе правил, когда приложение начинает расти и правила начинают слишком «разбрасываться» в запросе формы, мы можем создать классы правил, которые сделают эти наборы многократно используемыми и более понятными. Мне нравится создавать каталог Rules
внутри app/
и создавать класс, который будет предоставлять нужные мне правила:
// app/BirdSightingRules.php
class BirdSightingRules
{
public static function birdRules()
{
return [
'common_name' => 'required|string|max:255',
'species' => 'required|string|max:255',
'quantity' => 'nullable|integer|min:1',
];
}
public static function locationRules()
{
return [
'sighted_at' => 'required|date',
'latitude' => 'required|numeric',
'longitude' => ['required', 'numeric'],
];
}
public static function updateRules()
{
return [
//
];
}
}
Затем вернемся к запросу формы:
public function rules()
{
return array_merge(
BirdSightingRules::birdRules(),
BirdSightingRules::locationRules()
);
}
Пользовательские правила
В Laravel так много встроенных правил, что вам может понадобиться некоторое время, чтобы создать пользовательское правило, но иногда ваше приложение может иметь специфическую особенность, которая требует пользовательского правила валидации. В этом случае artisan поможет вам:
php artisan make:rule SightedInMarch
Будет создан файл в каталоге app/Rules
, который содержит пользовательское правило со следующими методами:
// app/Rules/SightedInMarch.php
class SightedInMarch implements Rule
{
public function passes($attribute, $value)
{
//
}
public function message()
{
return 'The validation error message.';
}
}
Внутри метода passes
вы можете создать свое пользовательское правило, которое должно возвращать булево значение, а внутри message
вам просто нужно вернуть строку с объяснением того, почему оно не прошло проверку:
public function passes($attribute, $value)
{
return preg_match('/^[0-9]{4}-03-[0-9]{2}/', $value);
}
public function message()
{
return 'Why are you watching birds in March?';
}
Затем вернитесь к набору правил и используйте это пользовательское правило с атрибутом sighted_at
:
// app/Rules/BirdSightingRules.php
public static function locationRules()
{
return [
'sighted_at' => ['required', 'date', new SightedInMarch],
'latitude' => 'required|numeric',
'longitude' => ['required', 'numeric'],
];
}
Теперь все запросы формы, использующие locationRules
, будут автоматически проверять атрибут sighted_at
, используя это новое правило. На этом мы завершаем очередную статью. До встречи в следующей!