Схема
В общем, я предлагаю придерживаться следующей схемы обмена сообщениями:
##### Успешный ответ
В случае успешного ответа возвращать код 200, а в теле ответа либо ничего, либо строку, либо массив/объект, в зависимости от контекста:
- `response('', 200)`
- `response('Сохранено!', 200)`
- `response(['a' => 123, 'b' => 'asd'], 200)`
##### Ошибка валидации
В случае ошибки валидации Laravel сам заботится об ответе (если конечно использовать `$request->validate`). Формат ответа будет такой (код ответа 422):
```
{
"message": "The given data was invalid.",
"errors": {
"field-1": [
"Error 1",
"Error 2"
],
"field-2": [
"Error 1",
"Error 2"
],
}
}
```
В случае, когда мы не можем использовать встроенную валидацию, я предлагаю просто придерживаться этого же формата. Объект "errors" здесь не является обязательным. То есть, в самом простом случае можно обойтись кодом 422 и полем "message".
##### Эксепшены
В случае критичной ошибки Laravel в продакшене отдает аналогичный ответ, как и в предыдущем пункте. Только код ошибки может быть разным. Например, код `$user = User::findOrfail(99999);` кинет исключение (если юзера 99999 не существует), а в браузер придет ответ с кодом 404 и телом:
```
{
"message": "No query results for model [App\\User] 99999"
}
```
В идеале, конечно, нужно стремиться к тому, чтобы конечный пользователь не видел этих эксепшенов. Во-первых, текст ошибки захардкожен в движок, он всегда будет на английском, и вряд ли сообщит что-то полезное пользователю. Во-вторых, тут может быть раскрыто немного внутренней информации, например класс App\\User.
Но т.к. идеала не существует, я считаю, что это — приемлемый вариант, особенно для прототипа. Предполагается, что если юзер не будет пытаться "хакать" систему, то таких эксепшенов он и не увидит. Также, эксепшены будут появляться в логе, и мы должны будем быстро на них отреагировать.
##### Ошибки логики, прав доступа и прочее
Бывает, что по логике приложения нужно показать пользователю ошибку. Например, "недостаточно денег на балансе". В принципе, здесь доступны разные варианты, но проще всего вернуть ответ в таком же формате, как возвращает Laravel. Нужно только вручную указать код ответа, написать сообщение и, если необходимо, добавить дополнительные данные:
```
response(['message' => 'Недостаточно денег на балансе'], 402)
response(['message' => 'Есть несколько ошибок', 'errors' => [...]], 403)
response(['message' => 'Есть несколько ошибок, вот вам доп.инфа', 'errors' => [...], 'anyData' => [...]], 403)
```
Единственный нюанс, который может возникнуть в будущем, это если Laravel в будущих версиях изменит формат ошибок, как это случилось в версии 5.5. Например, вместо "message" сделает "errorMessage". Тогда нам придется везде, где мы вручную кидаем ошибки, поменять это. Но подобные изменения происходят очень редко, так что серьезной опасности я тут не вижу. К тому же, всегда можно написать свой метод а-ля `custom_error`, и везде использовать его, вместо встроенного `response`. Тогда поменять придется только его реализацию.
В общем, если видишь слабые места здесь — говори прямо. Я скорее всего что-нибудь не учел, но думаю 95% случаев данная схема закроет.