Laravel5.3でAPIを簡単に作ってみる

今年の8月にLaravel5.3がリリースしましたね。

laravel-news.com

色々な変更がありましたが、個人的にはルーティングのファイルが別れたこともなかなか嬉しかったです。

大規模なプロジェクトになるとエンドポイントがたくさん増えてroute.phpがどんどん大きくなってしまいました。またRailsであってもroutes.rbが大きくなってしまっていました。

今回開発中の弊社の新サービスのLaravelのバージョンを5.3にあげたのでLaravelでの入門的なAPIの書き方について書こうと思います。

ルーティングの設定

まず、app/Providers/RouteServiceProvider.phpへルーティングファイルを登録します。

class RouteServiceProvider extends ServiceProvider { protected $namespace = 'App\Http\Controllers';

public function boot()
{
    //
    parent::boot();
}

public function map()
{
    $this->mapWebRoutes();
    $this->mapApiRoutes();
}

protected function mapWebRoutes()
{
    // 普通のルーティング
}

protected function mapApiRoutes()
{
    Route::group([
        // Kernel.phpでapiに登録されているミドルウェアを適応
        'middleware' => 'api',
        // Controllers/Api以下にあるクラスに限定する
        'namespace' => "{$this->namespace}\Api",
        // エンドポイントを/api/somethingの形にする
        'prefix' => 'api',
    ], function ($router) {
        // api.phpを登録する
        require base_path('routes/api.php');
    });
}

}

これでroutes/api.phpへルーティングを書くことができるようになりました。

コントローラを書く

Laravelには様々な機能があり、コントローラを書く上ではValidatorが特に重宝していると思います。

qiita.com

試しに"/api/test?id=1&date=2016-09-28&title=MatchinGood"という感じでアクセスできるAPIのコントローラを描いてみます。

namespace App\Http\Controllers\Api;

use Illuminate\Http\Request; use App\Http\Controllers\Controller;

class TestController extends Controller { public function test(Request $request) { $validator = Validator::make($request->all(), [ // 必須パラメータかつ整数 'id' => 'required|integer', // 必須パラメータかつY-m-dの形 'date' => 'required|date_format:"Y-m-d"', // 必須パラメータかつ文字列 'title' => 'required|string' ]);

    if ($validator->fails()) {
        return response()->json($validator->errors(), 422);
    }

    return response()->json(['status' => 'successful']);
}

}

こんな感じでどうでしょうか。煩雑になりがちなパラメータのバリデーションはすべてLaravelのValidatorに任せられます。公式ドキュメントには色々なバリデーションの種類がありますので適切なものを選択します。

APIなのでバリデーションが失敗した時の返り値もjsonである必要がありますが、$validator->errors()を使うとエラーの内容が取得できるのでそれを使うと楽できます。

ルーティング

コントローラがかけたのでいよいよapi.phpを書きます。

<?php Route::get('test', 'TestController@test'); RouteServiceProviderでnamespaceをApp\Http\Controllers\Apiで設定してあるのでnamespaceの先頭のApiは省くことができます。

おまけ

実はLaravelには$request->wantsJson()でリクエストヘッダーに"ContentType: application/json"がセットされているかどうか調べることができます。なので単純にcompanyというリソースの詳細画面に行くURIが"/company/1"で、わざわざ別のコントローラにAPIを書きたくないと思った時は

public function show(Company $company, Request $request) { if ($request->wantsJson()) { return $company; } return view('company.detail')->with('company', $company); } というふうにすることでリクエストのヘッダーに応じてjsonで返すことができます。

ここで、なぜ単純にEloquentのモデルをコントローラの返り値として返しているかというと、LaravelのEloquentのソースでは、

abstract class Model implements ArrayAccess, Arrayable, Jsonable, JsonSerializable, QueueableEntity, UrlRoutable { . . . public function __toString() { return $this->toJson(); } } となっていて、stringにキャストする際にtoJson()を呼んでいることがわかります。toJson()ではモデルの各カラムの値とリレーションをjsonの文字列にして返します。なのでこれでモデルをそのままjsonの形式で返すことができています。

より詳しい実装がきになる方は実際にソースコードを読むことをお勧めします。

laravel/framework Contribute to framework development by creating an account on GitHub. https://github.com/laravel/framework/blob/5.3/src/Illuminate/Database/Eloquent/Model.php