149
129

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ラクスAdvent Calendar 2017

Day 3

Laravelで作るRESTなWebアプリ

Last updated at Posted at 2017-12-02

#はじめに
プライベートでPHPフレームワークのLaravelを使ってWebアプリ制作を行っています。
Laravelにはルーティングという機能があり、特定のアドレスが特定のHTTPメソッドでリクエストされた際に、指定したコントローラの指定したメソッドを呼び出すという仕組みがあります。

web.php
<?php

Route::get('hello', 'HelloController@index');
Route::post('hello', 'HelloController@post');
HelloController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class HelloController extends Controller
{
    public function index(Request $request){
        return view('hello.index', ['msg' => "GETが送信されました"]);
    }
    
    public function post(Request $request){
        return view('hello.index',['msg' => "POSTが送信されました"]);
    }
}

上記の例では、helloというアクションがGETで呼び出された場合はHelloController内に記述されたindexメソッドを呼びます。
同様に、POSTで呼び出された場合はpostメソッドが呼び出されます。
アクションが同じでも、呼び出す際に指定したHTTPメソッドによって呼び出し先を変えることができるという点が非常に面白いです。

このようにHTTPメソッドごとにレスポンスを変化させことができるWebアプリはRESTなWebサービスと呼ばれます。
上記の通りLaravelのルーティング機能を使うことでRESTなWebサービスも開発できることから、RESTについての興味を持ち始めました。

今回はLaravelを使ってRESTな簡単なWebサービスを作成する方法を記載したいと思います。

#RESTであるためのルール
単にHTTPメソッドごとにレスポンスを変化させるだけではRESTであるとは呼べません。
RESTの提唱者であるRoy Fielding氏はRESTの設計原則は主に以下4つからなると述べています。

  • セッションなどの状態管理を行わない
  • 情報を操作する命令の体系が予め定義・共有されている
  • すべての情報は汎用的な構文で一意に識別される
  • 情報の内部に、別の情報や状態へのリンクを含めることができる

個人的に要約すると。

  • ステートレスであれ
  • HTTPメソッドの役割を意識して機能を分割せよ
  • URIをコロコロ変えるな
  • HTMLやXMLで表現できるようにせよ

上記全てが興味深い考え方ですが、今回特に注目したいのが、2つ目の項目です。

##HTTPメソッドの種類
現在利用できるHTTPメソッドは以下の9種類です。

メソッド 意味
GET リソースの取得
POST 子リースの作成、リソースへのデータ追加、そのほかの処理
PUT リソースの更新、リソースの作成
PATCH リソースの部分置換
DELETE リソースの削除
HEAD リソースののヘッダ(メタデータ)の取得
OPTION リソースがサポートしているメソッドの取得
TRACE 自分宛にリクエストメッセージを返す(ループバック)試験
CONNECT プロキシ動作のトンネル接続への変更

上記の中でも、システムに必要な主要機能であるCRUD特性を満たしているのは以下の4つです。

CRUD名 意味 メソッド
Create 作成 POST/PUT
Read 読み込み GET
Update 更新 PUT/PATCH
Delete 削除 DELETE

Laravelでは上記のCRUD特性をHTTPメソッドを切り替えながらRESTなWebサービスを作成することができます。

#Laravelで作るRESTfulなWebアプリを作る方法
LaravelではRESTを準拠したコントローラを自動で生成する仕組みがあります。

コントローラの生成はLaravelではお馴染みのartisanコマンドを使います。

php artisan make:controller RestappController --resource

上記のコマンドで特に重要なのは最後に付与している--resourceというオプションです。
このオプションを付与することによって、コントローラー内でCRUD特性の機能を一式セットにして登録して、扱えるようにしてくれます。
非常に親切なオプションですね。

それでは、上記のコマンドで作成したRestappController.phpの中身を確認してみましょう。

RestappController.php
<?php

namespace App\Http\Controllers;

use App\Restdata;
use Illuminate\Http\Request;

class RestappController extends Controller
{
    public function index()
    {
        //
    }

    public function create()
    {
        //
    }

    public function store(Request $request)
    {
        //
    }

    public function show($id)
    {
        //
    }

    public function edit($id)
    {
        //
    }

    public function update(Request $request, $id)
    {
        //
    }

    public function destroy($id)
    {
        //
    }
}

各メソッドの意味は以下の通りです。

機能 メソッド名
一覧表示 index
新規作成 create, store
レコード表示 show
更新処理 edit, update
削除処理 destroy

それでは、以下のようなルーティングの処理をweb.phpに追加します。

web.php
<?php

Route::resource('rest','RestappController');

上記は、このブログの上記にも記載させていただきましたLaravelのルーティング機能を実現している処理です。
注目べきは、Routeクラスのメソッドがgetpostではなくresourceとなっている点です。

Laravelでは以下の操作をすべてresourceで受け取り、受け付けたHTTPメソッドごとにコントローラの各メソッドを呼び出します。

リクエスト 実行するメソッド
/コントローラ名 index
/コントローラ名/create create
/コントローラ名 store(POST送信)
/コントローラ名/番号 show(番号 = ID)
/コントローラ名/番号/edit edit(番号 = ID)
/コントローラ名/番号 update(番号 = ID, PUT/PATCH送信)
/コントローラ名/番号 destroy(番号 = ID, DELETE 送信)

以下で、実際に動かしながら一つ一つの機能をテストしていきます。


なお、今回はあらかじめ、以下のような準備を行いました。

  • RestAppというLaravelプロジェクトの作成
  • Postgresにて、rest-appというデータベースを作成
  • rest-appデータベース内に名前とメッセージが登録可能なrestdataというテーブルを作成
  • restdataテーブル内にサンプルデータを2件登録

もしLaravelプロジェクトの内容が気になる方はGitHubにアップしておきましたので、ご確認ください。

マイグレーションやシードの設定もしているため、PHPの実行環境とPostgresがインストールされていれば同じようにテストすることができます。
※php artisan migrete でDBを更新することをお忘れなく


##indexメソッドとshowメソッドの動作確認
それでは、GETを受け付けるRestappController.phpindexメソッドshowメソッドを以下のように修正します。

RestappController.php
public function index()
{
    $items = Restdata::all();
    return $items->toArray();
}

public function show($id)
{
    $items = Restdata::find($id);
    return $items->toArray();
}

メソッド内で宣言されているResedataクラスとはLaravelで使用可能なEloquentという機能です。
JAVAで言うところの、DTOだと思ってくださって大丈夫でしょう。
Eloquentのallメソッドやfindメソッドを用いることで、データベースのデータを全件取得したり1行だけ取得したりすることができます。

さて、では、URLを叩いて結果を確認してみましょう。

ブラウザ上でコントローラ名をGETメソッドで叩きます。(今回はビルドインサーバで行います)

image.png

テーブル内のデータ一覧をJSON形式で取得することができました。

なぜこのようなことが実現できたかというと、Laravelではアクションメソッドからreturnされた配列のデータはJSON形式に変換して出力してくれるからです。

次は、1行検索を試してみます。
コントローラ名/ID でGETメソッドを叩きます。

image.png

今度は指定したIDのデータだけを取得することができました。

このようにGETメソッドだけでも叩き方を工夫するだけで、データの取り方を変えられることが確認できました。

##storeメソッドとcreateメソッドの動作確認

次は、POSTを受け付けるstoreメソッドに処理を追加して、データを挿入できるようにしましょう。

上記の表にある通り、createメソッドはGETを受け付けます。
実は、RESTfulアプリを作成する上で、createメソッドは必要ありません。
なぜなら、createメソッドは登録フォームを表示するだけのメソッドだからです。

本来、WebAPIなどを制作する場合は、クライアントからのリクエストを受け付ける窓口だけが存在すればよいため、画面を用意する必要がありません。
今回はせっかくなので、LaravelのRESTコントローラが気前よく用意してくれたcreateメソッドを使って、入力フォームを表示する処理だけ追加します。

RestappController.php
public function create()
{
    return view('rest.create');
}

public function store(Request $request)
{
    $restdata = new Restdata;
    $form = $request->all();
    unset($form['_token']);
    $restdata->fill($form)->save();
    return redirect('/rest');
}

そして、最も重要なstoreメソッドです。
こちらは、フォームから受け取った値を一度加工してからデータベースに格納しています。

ここでも、Eloquentが登場し、fillメソッドとsaveメソッドをメソッドチェーンで連結しています。
どちらのメッドも内部処理の想像がつくかと思いますが、fillメソッドが実行するSQL文のプレースホルダに値をバインドする処理で、saveメソッドがinsertする処理です。

次に入力フォームです。

create.blade.php
<html>
<head>
<title>REST_FORM</title>
</head>
<body>
<form action="/rest" method="POST">
{{ csrf_field() }}
NAME:<input type="text" name="name"><br>
MESSAGE:<input type="text" name="message"><br>
<input type="submit" value="send">
</form>
</body>
</html>

こちらは特に説明する必要もないほどシンプルな入力フォームです。
一点だけ注意しなければならないのがformタグ内に**{{ csrf_field() }}**というタグを埋め込まなければならないという点です。
Laravelでフォームを使ったデータ送信を行う場合は、CSRF対策のためにこのタグを入れなければExceptionが発生します。

意図しないところでWebサービスの脆弱性が生まれないようにするための安心設計です。
(最初、この仕様に気づいておらず、エラーの原因がさっぱりわかりませんでした。。。。)

それでは、データを追加してみましょう。

image.png

以上のようにフォームにデータを入力して、sendを押下します。

image.png

データを追加することができました。

##updateメソッドの動作確認
次はPUTメソッドを受け付けるupdateメソッドの動作確認です。

HTMLフォームはPUT,PATCH,DELETEアクションをサポートしていないため、ひと工夫が必要です。

さきほどのフォームにちょっと手を加えます。

create.blade.php
<html>
<head>
<title>REST_FORM</title>
</head>
<body>
<form action="/rest/1" method="POST">
{{ csrf_field() }}
<input type="hidden" name="_method" value="PUT">
NAME:<input type="text" name="name"><br>
MESSAGE:<input type="text" name="message"><br>
<input type="submit" value="send">
</form>
</body>
</html>

追加するのは {{ csrf_field() }} 直下の****というパラメータです。
このように記述することで、HTMLでもPUT送信することができます。

それでは、ID:1のユーザのコメントを更新するために、updateメソッドを以下のような処理を追加しましょう。

RestappController.php
public function create()
{
    return view('rest.create');
}

public function store(Request $request)
{
    $restdata = new Restdata;
    $form = $request->all();
    unset($form['_token']);
    $restdata->fill($form)->save();
    return redirect('/rest');
}

updateメソッドを呼び出すにはコントローラ名/IDをPUTメソッドで叩きます。
(今回はform要素のaction属性にID:1を直接指定しています。)

image.png

image.png

ID:1 の messageがupdateメソッドにより「Hello World!」から「HELLO!」に修正されました。

##destoryメソッドの動作確認
最後にdeleteを受け付けるdestoryメソッドによるデータの削除です。
destoryメソッドを以下のように修正します。

RestappController.php
public function destroy($id)
{
    $items = Restdata::find($id)->delete();
    return redirect('/rest');
}

Eloquent での削除処理は非常にシンプルです。
findメソッドで1行検索した後にdeleteメソッドをメソッドチェーンで連結することで、選択した行を削除することができます。

画面側はIDを指定するだけで大丈夫です。

create.blade.php
<html>
<head>
<title>REST_FORM</title>
</head>
<body>
<form action="/rest/1" method="POST">
{{ csrf_field() }}
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="send">
</form>
</body>
</html>

image.png

image.png

ID:1のデータを削除することができました。

#おわりに
いかがでしたでしょうか。
HTTPメソッドを切り替えるだけで、アクションを切り替えることができ、ルーティングも非常にシンプルになったと思います。
CRUD特性をすべて実装しているにも関わらず、コントローラがシンプルというのも素敵です。

DBへのアクセス処理を密結合にならないように実現することで、再利用性が高まり、利用者にも優しいサービスになります。
また、開発者目線でも便利な処理は開発者間で使いまわしやすくすることは大切ですね。

#参考図書・参考サイト
Webを支える技術 ―― HTTP,URI,HTML,そしてREST
http://gihyo.jp/book/2010/978-4-7741-4204-3

PHPフレームワーク Laravel入門
http://www.shuwasystem.co.jp/products/7980html/5258.html

IT用語時点 e-Words REST
http://e-words.jp/w/REST.html

HTTPメソッド(CRUD)についてまとめた
https://qiita.com/Ryutaro/items/a9e8d18467fe3e04068e

PUT か POST か PATCH か?
https://qiita.com/suin/items/d17bdfc8dba086d36115

Laravel 5.3 コレクション
https://readouble.com/laravel/5.3/ja/collections.html#method-toarray

Laravel 5.1 HTTPルーティング
https://readouble.com/laravel/5.1/ja/routing.html#form-method-spoofing

149
129
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
149
129

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?