Исключения Laravel: ловим, обрабатываем и создаем собственные

Laravel Exceptions

Обычно веб-разработчики не следят за ошибками. Если что-то идет не так, то мы частенько видим дефолтный текст ошибки Laravel: «Whoops, something went wrong» или, что еще хуже, код исключения, который посетителю совсем ни к чему. Поэтому я решил написать пошаговую статью о том, как элегантно обрабатывать ошибки и показывать посетителю правильную информацию о произошедшем.

Примечание: в этой статье также будет показан пример создания собственной службы с внедрением зависимости и обработка исключений, создаваемых службой.

Подготовка: Задача поиска пользователя

Итак, у нас есть очень простой пример — форма для поиска пользователя по его идентификатору.

У нас есть два маршрута:

И контроллер с двумя методами:

В файле resources/views/users/index. blade. php находится сама форма:

Если мы ищем существующего пользователя и он найден, мы видим такой результат:

Всё это находится в resources/views/users/search. blade. php:

Но это в идеальном случае, а что, если пользователь не найден?

Обработка исключений

Давайте вернемся в реальный мир. Мы не проверяем существование пользователя, в контроллере мы только делаем:

И, если пользователь не найден, то получим это:

Или, понятное дело, мы можем задать APP_DEBUG=false в файле .env, и тогда браузер просто покажет пустую страницу с «Whoops, looks like something went wrong». Но для нашего посетителя все это совершенно бесполезно.

Еще одно быстрое исправление, которое мы можем сделать, это использовать User::findOrFail() вместо просто find() — тогда, если пользователь не найден, Laravel покажет страницу 404 с текстом «Sorry, the page you are looking for could not be found». Но это дефолтная страница ошибки для всего сайта. Для посетителя она, опять таки, бесполезна.

Поэтому нам нужно отлавливать ошибки, обрабатывать их и перенаправлять обратно в форму с действительно понятным сообщением об ошибке.

Нам нужно знать тип исключения и имя класса, которое оно будет возвращать. В случае с findOrFail() будет выдано Eloquent исключение ModelNotFoundException, поэтому нам нужно сделать так:

Теперь давайте покажем ошибку в Blade:

Результат:

Отлично, мы отобразили ошибку! Но это еще не идеал, верно? Вместо $exception->getMessage() нам нужно показать наше собственное сообщение:

Финальный вариант!

Перемещаем обработку ошибок в Сервис

На данный момент мы взяли очень простой пример одного действия в контроллере — поиск пользователя. В реальном приложении все гораздо сложнее — обычно контроллер вызывает какой-нибудь внешний сервис или метод пакета, которые могут завершиться с какими-угодно ошибками.

Давайте создадим свой собственный сервис, который, по сути, делает то же самое, но будет генерировать исключение, поэтому контроллеру даже не потребуется знать текст сообщения.

Давайте переместим нашу логику в app/Services/UserService. php:

А в контроллере нам нужно вызвать этот сервис. Для начала мы внедрим его в метод __construct():

Если вы не знакомы с внедрением зависимостей и как работает контейнер Laravel IOC, то вот официальная документация.

А вот так теперь выглядит наш метод search():

Обратите внимание, мы снова можем использовать $exception->getMessage(), вся проверка ошибок и логика сообщений происходит внутри службы. Мы удалили это из контроллера, он не должен заниматься этим.

Следующий Шаг: Создание собственного класса исключений

Последняя глава этой статьи посвящена улучшению архитектуры. Это когда ваш сервис генерирует свое собственное исключение, связанное с этой конкретной ошибкой, и, в зависимости от ошибки, может быть несколько классов исключений. Хорошим примером такой архитектуры является библиотека Stripe, ее использование выглядит так:

Итак, как мы можем создать наш собственный класс исключений? Очень просто — с помощью команды Artisan:

Сгенерируется app/Exceptions/UserNotFoundException. php:

Здесь же ничего нет, верно? Давайте заполним наше исключение логикой.
В этом классе может быть два метода:

Итак, для этого примера мы cделаем метод report():

А вот так мы вызываем это исключение из контроллера:

Итак, это всё, что я хотел рассказать вам об обработке исключений и использовании Сервисов.

Я понимаю, что мой пример очень упрощен, и другие люди могут использовать исключения иными способами, но я надеюсь, что в этой статье дан основой обзор исключений и причин, по которым вы должны их использовать.

Подробнее об исключениях и обработке ошибок: официальная документация Laravel.

Laravel 5.5 вывод ошибок валидации для API

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

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

Чтобы вы понимали, о чём я сейчас говорю, например, при отправке запроса к API, ошибки валидации придут в подобном формате:
error-default-form-request

Обработка исключений из единого места

Изначально этот метод содержит код:

Но можно его немного модифицировать, добавив правило: если приходит AJAX запрос, или запрос содержит заголовок Accept: application/json, то, отправим ответ в формате JSON

В результате, получим ответ, который не показывает все ошибки валидации. В этом случае при любой из ошибок всегда будет одно сообщение "The given data was invalid." (в случае валидации):
habdler. php

Но, как я писал выше, можно отловить исключения только определённого типа. В данном случае, нас интересуют только исключения валидации, экземпляра ValidationException.

В этом коде мы проверяем, является ли объект исключения экземпляром ValidationException, который как раз и содержит в себе информацию об ошибках валидации.validation

Вот такой формат уже приемлем для того, чтобы удобно их обрабатывать на клиенте. Дальнейшая обработка зависит от ваших требования и задач.

Вынесение логики обработки исключений в отдельный Form Request

Гораздо лучше было бы создать правила, примениемые только к некоторым форм-реквестам. И, мы можем это сделать.

Для этого, в папке app/Http/Requests создадим свою реализацию FormRequest-класса, который будет возвращать ошибки валидации в JSON-е:

И теперь, любой FormRequest-класс, в котором нужен вывод ошибок в JSON, наследуем от этого класса, например:

И в итоге, получим данные в формате:
api-form-request

В версиях Laravel ниже 5.5, метод называется response а не failedValidation.

Резюме

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

Источники:

https://laravel. demiart. ru/isklyucheniya-laravel-lovim-obrabatyvaem-i-sozdaem-sobstvennye/

https://badcode. ru/laravel-5-5-vyvod-oshibok-validatsii-dlia-api/

Понравилась статья? Поделиться с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: