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

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://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: :???: :?: :!: