以下どちらかの実装でjsonレスポンスにできる。
failedValidation()
をオーバーライドするAccept
またはX-Requested-With
を追加するLaravelのバージョンは6.15.0です。
failedValidation()
のオーバーライドフォームリクエストクラスのfailedValidation()
をオーバーライドすることでjsonレスポンスかつメッセージをカスタマイズすることも可能。以下はサインアップのエンドポイントを想定したリクエストの例。
<?php
namespace App\Http\Requests;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
class SignUpRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'user_id' => 'required',
'password' => 'required'
];
}
public function messages()
{
return [
'user_id.required' => 'ユーザーIDは必須です。',
'password.required' => 'パスワードは必須です。',
];
}
protected function failedValidation(Validator $validator)
{
throw new HttpResponseException(
response()->json([
'message' => $validator->errors()->toArray(),
], 403)
);
}
}
Accept
またはX-Requested-With
を追加するエクセプションハンドラを変更していない場合、バリデーションエラー発生時はIlluminate/Foundation/Exceptions/Handler::render()
でレスポンス生成が行われる。
// Illuminate/Foundation/Exceptions/Handler.php
public function render($request, Exception $e)
{
if (method_exists($e, 'render') && $response = $e->render($request)) {
return Router::toResponse($request, $response);
} elseif ($e instanceof Responsable) {
return $e->toResponse($request);
}
$e = $this->prepareException($e);
if ($e instanceof HttpResponseException) {
return $e->getResponse();
} elseif ($e instanceof AuthenticationException) {
return $this->unauthenticated($request, $e);
} elseif ($e instanceof ValidationException) {
return $this->convertValidationExceptionToResponse($e, $request);
}
return $request->expectsJson()
? $this->prepareJsonResponse($request, $e)
: $this->prepareResponse($request, $e);
}
今回はバリデーションエラーの場合なのでconvertValidationExceptionToResponse()
が実行される。
// Illuminate/Foundation/Exceptions/Handler.php
protected function convertValidationExceptionToResponse(ValidationException $e, $request)
{
if ($e->response) {
return $e->response;
}
return $request->expectsJson()
? $this->invalidJson($request, $e)
: $this->invalid($request, $e);
}
expectsJson()
はヘッダにX-Requested-With: XMLHttpRequest
が含まれているか、ヘッダにAccept: .../json
もしくはAccept: ...+json
が含まれている場合にjsonレスポンスを返却する。
そのためミドルウェアでヘッダを追加することでjsonレスポンスが取得できる。
<?php
// app/Http/Middleware/EnforceJson.php
namespace App\Http\Middleware;
use Closure;
/**
* @see https://stackoverflow.com/questions/44453221/how-to-set-header-for-all-requests-in-route-group
*/
class EnforceJson
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$request->headers->set('Accept', 'application/json');
return $next($request);
}
}
<?php
// app/Http/Kernel.php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
// ...
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\EnforceJson::class, // 追加
],
];
// ...
}
個人的には返却するメッセージを変更できるのでfailedValidation()
をオーバーライドするほうが好みです。
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント