Заголовки для API

Февраль, 2024

как вернуть json

# Проблема

Например, ошибка валидации перенаправляет на предыдущий адрес и добавляет текст ошибок в сессию.
Критическая ошибка отобразит html страницу с подробным описанием или просто с текстом «Error 500», если выключен debug.

Но что если в ответе необходим json? Для валидации сказано, что если запрос ожидает json, то фреймворк автоматически вернёт его с соответствующим кодом. Что это значит?

# Теория

Laravel может автоматически возвращать json для обычных или XHR запросов. Поведение управляется с помощью заголовков:

Accept сообщает приложению какой тип данных ожидается в ответе.
Content-Type сообщает о типе данных в запросе или ответе.

# Решение

Таким образом, необходимо с клиента отправить правильные заголовки для json:

Accept: application/json
Content-Type: application/json

Согласно документации Content-Type укажет фреймворку, что входящие данные являются json и таким образом можно будет работать с ними как с обычными или массивом, не прибегая к предварительному декодированию с помощью json_decode()

# Ответ приложения

Согласно документации метод response()->json() автоматически конвертирует данные в json и устанавливает необходимые заголовки, поэтому никаких дополнительных действий не требуется.

# Всегда json

Если Laravel используется как API и всегда запрос/ответ должны быть в json, то можно установить заголовки в middleware:

1public function handle(Request $request, Closure $next)
2{
3 $request->headers->set('Accept', 'application/json');
4 $request->headers->set('Content-Type', 'application/json');
5 
6 return $next($request);
7}
highlight by torchlight.dev

Это позволит клиентам не устанавливать заголовки, но вопрос действительно ли это так необходимо?

Другой вариант - проверять в middleware заголовки и возвращать 406 Not Acceptable , или любой другой код ошибки. На мой взгляд, так будет правильнее.

1public function handle(Request $request, Closure $next)
2{
3 if (!$request->expectsJson()) {
4 return response()->json([], 406);
5 }
6 
7 return $next($request);
8}
highlight by torchlight.dev

А ещё лучше это сделать на уровне nginx (web-сервера), а не php.

1if ($http_accept != 'application/json') {
2 return 406;
3}
highlight by torchlight.dev