Получить код ошибки 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. И, так же, по примеру, вы с легкостью сможете реализовать любой формат вывода, который нужен.

Laravel API Errors and Exceptions: How to Return Responses

API-based projects are more and more popular, and they are pretty easy to create in Laravel. But one topic is less talked about – it’s error handling for various exceptions. API consumers often complain that they get “Server error” but no valuable messages. So, how to handle API errors gracefully? How to return them in “readable” form?

Main Goal: Status Code + Readable Message

For APIs, correct errors are even more important than for web-only browser projects. As people, we can understand the error from browser message and then decide what to do, but for APIs – they are usually consumed by other software and not by people, so returned result should be “readable by machines”. And that means HTTP status codes.

Every request to the API returns some status code, for successful requests it’s usually 200, or 2xx with XX as other number.

If you return an error response, it should not contain 2xx code, here are most popular ones for errors:

Status Code Meaning
404 Not Found (page or other resource doesn’t exist)
401 Not authorized (not logged in)
403 Logged in but access to requested area is forbidden
400 Bad request (something wrong with URL or parameters)
422 Unprocessable Entity (validation failed)
500 General server error

Notice that if we don’t specify the status code for return, Laravel will do it automatically for us, and that may be incorrect. So it is advisable to specify codes whenever possible.

In addition to that, we need to take care of human-readable messages. So typical good response should contain HTTP error code and JSON result with something like this:

Ideally, it should contain even more details, to help API consumer to deal with the error. Here’s an example of how Facebook API returns error:

Usually, “error” contents is what is shown back to the browser or mobile app. So that’s what will be read by humans, therefore we need to take care of that to be clear, and with as many details as needed.

Now, let’s get to real tips how to make API errors better.

Tip 1. Switch APP_DEBUG=false Even Locally

There’s one important setting in .env file of Laravel – it’s APP_DEBUG which can be false or true.

If you turn it on as true, then all your errors will be shown with all the details, including names of the classes, DB tables etc.

It is a huge security issue, so in production environment it’s strictly advised to set this to false.

But I would advise to turn it off for API projects even locally, here’s why.

By turning off actual errors, you will be forced to think like API consumer who would receive just “Server error” and no more information. In other words, you will be forced to think how to handle errors and provide useful messages from the API.

Tip 2. Unhandled Routes – Fallback Method

First situation – what if someone calls API route that doesn’t exist, it can be really possible if someone even made a typo in URL. By default, you get this response from API:

And it is OK-ish message, at least 404 code is passed correctly. But you can do a better job and explain the error with some message.

To do that, you can specify Route::fallback() method at the end of routes/api. php, handling all the routes that weren’t matched.

The result will be the same 404 response, but now with error message that give some more information about what to do with this error.

Tip 3. Override 404 ModelNotFoundException

One of the most often exceptions is that some model object is not found, usually thrown by Model::findOrFail($id). If we leave it at that, here’s the typical message your API will show:

It is correct, but not a very pretty message to show to the end user, right? Therefore my advice is to override the handling for that particular exception.

We can do that in app/Exceptions/Handler. php (remember that file, we will come back to it multiple times later), in render() method:

We can catch any number of exceptions in this method. In this case, we’re returning the same 404 code but with a more readable message like this:

Tip 4. Catch As Much As Possible in Validation

In typical projects, developers don’t overthink validation rules, stick mostly with simple ones like “required”, “date”, “email” etc. But for APIs it’s actually the most typical cause of errors – that consumer posts invalid data, and then stuff breaks.

If we don’t put extra effort in catching bad data, then API will pass the back-end validation and throw just simple “Server error” without any details (which actually would mean DB query error).

Let’s look at this example – we have a store() method in Controller:

Our FormRequest file app/Http/Requests/StoreOfficesRequest. php contains two rules:

If we miss both of those parameters and pass empty values there, API will return a pretty readable error with 422 status code (this code is produced by default by Laravel validation failure):

As you can see, it lists all fields errors, also mentioning all errors for each field, not just the first that was caught.

Now, if we don’t specify those validation rules and allow validation to pass, here’s the API return:

That’s it. Server error. No other useful information about what went wrong, what field is missing or incorrect. So API consumer will get lost and won’t know what to do.

So I will repeat my point here – please, try to catch as many possible situations as possible within validation rules. Check for field existence, its type, min-max values, duplication etc.

Tip 5. Generally Avoid Empty 500 Server Error with Try-Catch

Continuing on the example above, just empty errors are the worst thing when using API. But harsh reality is that anything can go wrong, especially in big projects, so we can’t fix or predict random bugs.

On the other hand, we can catch them! With try-catch PHP block, obviously.

Imagine this Controller code:

It’s a fictional example, but pretty realistic. Searching for a user with email, then creating a record, then doing something with that record. And on any step, something wrong may happen. Email may be empty, admin may be not found (or wrong admin found), service method may throw any other error or exception etc.

There are many way to handle it and to use try-catch, but one of the most popular is to just have one big try-catch, with catching various exceptions:

As you can see, we can call abort() at any time, and add an error message we want. If we do that in every controller (or majority of them), then our API will return same 500 as “Server error”, but with much more actionable error messages.

Tip 6. Handle 3rd Party API Errors by Catching Their Exceptions

These days, web-project use a lot of external APIs, and they may also fail. If their API is good, then they will provide a proper exception and error mechanism (ironically, that’s kinda the point of this whole article), so let’s use it in our applications.

As an example, let’s try to make a Guzzle curl request to some URL and catch the exception.

As you may have noticed, the Github URL is invalid and this repository doesn’t exist. And if we leave the code as it is, our API will throw.. guess what.. Yup, “500 Server error” with no other details. But we can catch the exception and provide more details to the consumer:

Tip 6.1. Create Your Own Exceptions

We can even go one step further, and create our own exception, related specifically to some 3rd party API errors.

Then, our newly generated file app/Exceptions/GithubAPIException. php will look like this:

We can even leave it empty, but still throw it as exception. Even the exception name may help API user to avoid the errors in the future. So we do this:

Not only that – we can move that error handling into app/Exceptions/Handler. php file (remember above?), like this:

Final Notes

So, here were my tips to handle API errors, but they are not strict rules. People work with errors in quite different ways, so you may find other suggestions or opinions, feel free to comment below and let’s discuss.

Finally, I want to encourage you to do two things, in addition to error handling:

Источники:

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

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

https://laraveldaily. com/laravel-api-errors-and-exceptions-how-to-return-responses/

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

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