apiサーバ@laravel8で、returnするjsonのフォーマットをResponse::macroを使って、統一規格にしてみた
参考URL
https://saitoblog.page/posts/2021-05-23/
1. サービスプロバイダ(全体で使う関数)を作る
1 2 |
php artisan make:provider ApiResponseServiceProvider Provider created successfully. |
2. 実装する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use Illuminate\Support\Facades\Response; // 追加 class ApiResponseServiceProvider extends ServiceProvider { public function boot() { Response::macro('ApiJsonResponse', function ($data) { return response()->json( $data ); }); } /** * Register services. * * @return void */ public function register() { // } /** * Bootstrap services. * * @return void */ } |
3. laravelシステム(app/config/app.php)に登録する
1 2 3 4 5 6 7 |
'providers' => [ // ..... // apiのjsonレスポンスを統一するための自作プロバイダ App\Providers\ResponseApiServiceProvider::class, ], |
4. 使ってみる
routes/api.php
1 2 3 |
Route::get('/test', function () { return response()->ApiJsonResponse(['message' => 'hello, world']); }); |
ちゃんとJSONで返ってくる
http://localhost/laravel8/public/api/test
{“message”:”hello, world”}
5. 正常終了とエラー終了で返すJSONを分けてみた
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
class ApiResponseServiceProvider extends ServiceProvider { public function boot() { // 正常終了 Response::macro('ApiSuccess', function ($summary, $details) { return response()->json( [ 'success' => true, 'summary' => $summary, 'details' => $details ]); }); // 処理に失敗した時 Response::macro('ApiFailed', function ($summary, $details) { return response()->json( [ 'success' => false, 'summary' => $summary, 'details' => $details ]); }); // エラー時 Response::macro('ApiError', function ($summary, $details, $error_code) { return response()->json( [ 'success' => false, 'summary' => $summary, 'details' => $details ], $error_code); }); // Restful APIのルーティング(routes/api.php)で、対応するモデルが見つからない時 Response::macro('ApiMissing', function () { return response()->json([ 'success'=>false, 'summary'=>'Not Found...', 'details'=>'Invalid ID' ]); }); } |
6. 正常終了時のJSONレスポンス
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public function show(Station $station) { // // jsonで結果を返す // return response()->json([ // 'success' => true, // 'message' => 'Show Success!', // // 生成したレコードの値を返す。リレーション先も! // 'details' => Station::with('lines')->where('id', $station->id)->get() // ]); // こういう風に書き換える return response()->ApiSuccess( 'Show Success!', Station::with('lines')->where('id', $station->id)->get()->toArray() ); } |
7. 処理失敗時のJSONレスポンス
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public function store(Request $request) { //バリデーションルールを設定 $validator = \Validator::make($request->all(), [ 'line_id' => 'required|max:255|exists:lines,id', 'name' => 'required|max:255', ]); //バリデーションルールでエラーの場合 if ($validator->fails()) { // return response()->json([ // 'success' => false, // 'summary' => 'Insert Failed', // 'details' => $validator->errors() // ]); // こういう風に書き換える return response()->ApiFailed( 'Insert Failed', $validator->errors() ); } |
8. エラー時の処理
app/Exceptions/Handler.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class Handler extends ExceptionHandler { public function render($request, $exception) { // APIの場合はエラー画面ではなく、JSONでエラーコードとメッセージを返す if ( $request->is('api/*') ) { // HTTPエラー if($this->isHttpException($exception)){ return response()->ApiError( 'HTTP ERROR!!', $exception->getMessage(), $exception->getStatusCode() ); } // HTTPエラーじゃないけど、laravel的エラー。400(Bad Request)を返す return response()->ApiError( 'LARAVEL ERROR!!', $exception->getMessage(), 400 ); } return parent::render($request, $exception); } |
9. Restful APIのルーティング(routes/api.php)で、対応するモデルが見つからない時
http://localhost/laravel8/public/api/station/9999
routes/api.phpで以下のように書くと、エラー処理してくれる
1 2 3 4 5 6 |
// restful CRUD apiでレコードが見つからない場合に返すJSON function NotFoundResponse(Request $request){ return response()->ApiMissing(); } use App\Http\Controllers\StationController; Route::resource('station', StationController::class)->missing("NotFoundResponse"); |
レスポンス・マクロの粒度というか、どのくらいでまとめるかがキモやな。
とりあえず、正常・失敗・エラー・対応モデルなし(invalid ID)の4種類で書いてみた。