☆Yuus Memo☆
非エンジニアの方でも業務を効率化できるプログラムを紹介します!
Laravel

Laravel + Vue.jsでGoogleカレンダーのクローンを作ろう!!【Laravel8対応】API作成編②

皆さんこんにちは!!

Laravel8とVue.jsを使用して「スケジュール管理アプリ」を作成するチュートリアルの第3回目は、LaravelでAPI機能(コントローラとルーター)を実装してAPI機能を完成させます。

前回までの記事を、まだご覧になっていない方は、お先にご覧ください。

コントローラーの作成

今回作成しているアプリケーションでのLaravelの役割はデータの管理をするためのサーバーとして使用します。
従ってビューの部分は今回は不要となります。
代わりにコントローラはモデルで取得した値をJSONとしてクライアント(フロントエンド)に返却したり、クライアントからJSONで受け取ったデータを、データベースへ保存したり、削除したりします。
前回、データを管理するデータベーステーブルとデータベースを操作するためのモデルを作成したので、今回は、クライアントとの橋渡しを行う部分を作成します。

カレンダーコントローラの作成

早速ターミナルを開き、次のコマンドを実行して下さい。

my-calendar $  php artisan make:controller CalendarController

「/app/Http/Controllers/」以下に「CalendarController.php」というコントローラーが作成されます。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class CalendarController extends Controller
{
    //
}

このクラスファイルの中に、処理を書いていきます。
まずカレンダーデータを取得する処理を以下のように書いて下さい。

<?php

namespace App\Http\Controllers;

use App\Models\Calendar;    // 追加
use Illuminate\Http\Request;

class CalendarController extends Controller
{
   // 追加
    public function index()
    {
        Calendar::all();
    }
   // ここまで
}

「indexメソッド」はデータの一覧を取得するメソッドです。
続いて、このメソッドを呼び出すルーティングをルーターファイルに記述します。

「/routes/api.php」を開いてみて下さい。
初期の状態では次の様な内容になっています。

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
    return $request->user();
});

routesディレクトリの中のファイルは、ブラウザからのURLアクセスやAPIによるアクセスに対してのルーティングを設定するファイルが格納されています。

api.phpは主にAPIによるアクセスに対してのルーティングを記述するファイルになります。
次の様に編集して下さい。

<?php

use App\Http\Controllers\CalendarController; // コントローラーを追加
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
    return $request->user();
});

Route::get('/calendars', [CalendarController::class, 'index']); // 追加

追記が終わったら、「php artisan serve」でサーバーを立ち上げて下さい。

ユーザー登録を行い、カレンダーデータを作っておいて下さい。

CURLで確認するので、ターミナルで次のように実行して下さい。

CURLコマンドが無い方は次のページを参考にインストールして下さい。
それぞれ、簡単な使い方も確認してください。

 my-calendar $ curl  http://localhost:8000/api/calendars

## 次の様なデータが返れば成功です。
[
{"id":1,"name":"予定","color":"red","visibility":1,"user_id":1,"created_at":"2020-09-05T00:00:00.000000Z","updated_at":"2020-09-05T00:00:00.000000Z"},
{"id":2,"name":"仕事","color":"blue","visibility":1,"user_id":1,"created_at":"2020-09-05T00:00:00.000000Z","updated_at":"2020-09-05T00:00:00.000000Z"}
]

実際にデータベースへ登録してあるデータがJSON形式で取得できたと思います。
続けて、IDを指定して一つだけのデータを取得するAPIを CalendarControllerへ追記します。

    public function show(int $id)
    {
        return response()->json(Calendar::find($id));
    }


all()、find() メソッドの詳細は Laravel 8.x Eloquentの準備をご確認ください。

ルーティングも追記します。

Route::get('/calendars/{id}', [CalendarController::class, 'show']);

{id}で受け取る部分がshowメソッドの引数として使用できます。

CURLで確認するので、ターミナルで次のように実行して下さい。

my-calendar $  curl  http://localhost:8000/api/calendars/1

## 次の様なデータが返れば成功です。

{"id":1,"name":"予定","color":"red","visibility":1,"user_id":1,"created_at":"2020-09-05T00:00:00.000000Z","updated_at":"2020-09-05T00:00:00.000000Z"}

指定したIDのデータが取得できたかと思います。
詳しい解説は公式ドキュメントを見ていただくと分かりますが、Eloquentという機能を利用することで、簡単にデータが取得できる事が分かると思います。

カレンダーデータの作成、更新、削除

データの取得は上記の様に簡単に出来ることが分かったと思います。
続いては、データの登録などのPOST処理などを書いていきます。

基本的にコントローラにメソッドを書いてルーティングを設定するので流れは同じです。
まとめてCalendarControllerへ書いていきます。

// 新規
public function create(Request $request)
    {
        $calendar = new Calendar();

        return $this->_saveCalendar($request, $calendar);
    }

   // 更新
    public function save(Request $request)
    {
        $calendar = Calendar::find($request->id);

        return $this->_saveCalendar($request, $calendar);
    }
 
   // 削除
    public function destroy(Request $request)
    {
        $calendar = Calendar::find($request->id);

        if ($calendar->delete()) {
            return response()->json($calendar);
        } else {
            return response()->json(['error', 'Delete Error']);
        }
    }
    
   // データ保存処理
    private function _saveCalendar(Request $request, $calendar)
    {
        $calendar->name = $request->input('name');
        $calendar->color = $request->input('color');
        $calendar->visibility = $request->input('visibility');
        $calendar->user_id = $request->input('user_id');

        if ($calendar->save()) {
            return response()->json($calendar);
        } else {
            return response()->json(['error' => 'Save Error']);
        }
    }

続いてapi.phpへも追記します。

Route::post('/calendars', [CalendarController::class, 'create']);
Route::put('/calendars/{id}', [CalendarController::class, 'save']);
Route::delete('/calendars/{id}', [CalendarController::class, 'destroy']);

Laravelでは、同じURIでもget,post,put,patch,deleteの複数のHTTP動詞に振り分けてルートを定義することが可能になります。

Route::の次にくるHTTP動詞によって、適応されるルートが異なってきます。詳細はLaravel 8.x ルーティングをご覧ください。

ターミナルで下記を実行してみて下さい。

my-calendar $  curl -X POST -d '{"name": "curl-test", "color":"blue","visibility":1,"user_id":1}' -H 'Content-Type: application/json' http://localhost:8000/api/calendars

## 次の様なデータが返れば成功です。
{"name":"curl-test","color":"blue","visibility":1,"user_id":1,"updated_at":"2021-09-13T11:35:53.000000Z","created_at":"2021-09-13T11:35:53.000000Z","id":5}

データベースを確認すると、データが登録できていることが確認できると思います。
同様に更新、削除も確認します。

my-calendar $  curl -X PUT -d '{"name": "curl-update-test", "color":"red","visibility":1,"user_id":1}' -H 'Content-Type: application/json' http://localhost:8000/api/calendars/1

## 次の様なデータが返れば成功です。
{"id":1,"name":"curl-update-test","color":"red","visibility":1,"user_id":1,"created_at":"2020-09-05T00:00:00.000000Z","updated_at":"2021-09-13T11:54:18.000000Z"}

curl -X DELETE http://localhost:8000/api/calendars/1
## 次の様なデータが返れば成功です。
{"id":1,"name":"curl-update-test","color":"red","visibility":1,"user_id":1,"created_at":"2020-09-05T00:00:00.000000Z","updated_at":"2021-09-13T11:54:18.000000Z"}

それぞれ、CURLからのリクエストでルーティングに設定した通りのコントローラのメソッドが実行され、データが処理されたと思います。

お疲れ様です。
カレンダーのAPI機能は作成完了です!!

本来なら、バリデーションなどを書くのですが、その辺りも最後に「リファクタリング編」として実装します。

現在のカレンダーコントローラーの全文を載せておきます。

<?php

namespace App\Http\Controllers;

use App\Models\Calendar;
use Illuminate\Http\Request;

class CalendarController extends Controller
{
    public function index()
    {
        return response()->json(Calendar::all());
    }

    public function show(int $id)
    {
        return response()->json(Calendar::find($id));
    }


    public function create(Request $request)
    {
        $calendar = new Calendar();

        return $this->_saveCalendar($request, $calendar);
    }

    public function save(Request $request)
    {
        $calendar = Calendar::find($request->id);

        return $this->_saveCalendar($request, $calendar);
    }

    public function destroy(Request $request)
    {
        $calendar = Calendar::find($request->id);

        if ($calendar->delete()) {
            return response()->json($calendar);
        } else {
            return response()->json(['error', 'Delete Error']);
        }
    }

    private function _saveCalendar(Request $request, $calendar)
    {
        $calendar->name = $request->input('name');
        $calendar->color = $request->input('color');
        $calendar->visibility = $request->input('visibility');
        $calendar->user_id = $request->input('user_id');

        if ($calendar->save()) {
            return response()->json($calendar);
        } else {
            return response()->json(['error' => 'Save Error']);
        }
    }
}

イベントコントローラーの作成

ほぼカレンダーコントローラーと同じ流れなので、CRUD処理を書いたコードを記載します。

ターミナルで次のコマンドを実行しコントローラーを作成し、EventController.phpを次の様に編集してください。

my-calendar $ php artisan make:controller EventController
<?php

namespace App\Http\Controllers;

use App\Models\Event;
use Illuminate\Http\Request;

class EventController extends Controller
{
    public function index()
    {
        return response()->json(Event::all());
    }

    public function show(int $id)
    {
        return response()->json(Event::find($id));
    }

    public function create(Request $request)
    {
        $event = new Event();

        return $this->_saveEvent($request, $event);
    }

    public function save(Request $request)
    {
        $event = Event::find($request->id);

        return $this->_saveEvent($request, $event);
    }

    public function destroy(Request $request)
    {
        $event = Event::find($request->id);

        if ($event->delete()) {
            return response()->json($event);
        } else {
            return response()->json(['error', 'Delete Error']);
        }
    }


    public function _saveEvent(Request $request, $event)
    {
        $event->name = $request->input('name');
        $event->start = new Carbon($request->input('start')); // JSからのデータを日時形式に変換
        $event->end = new Carbon($request->input('end')); // JSからのデータを日時形式に変換
        $event->timed = $request->input('timed');
        $event->calendar_id = $request->input('calendar_id');
        $event->description = $request->input('description');
        $event->color = $request->input('color');

        if ($event->save()) {
            return response()->json($event);
        } else {
            return response()->json(['error' => 'Save Error']);
        }
    }
}

大体カレンダーコントローラーと同じですね。
ルーティングも次の様に追記します。

  Route::get('/events', [EventController::class, 'index']);
    Route::get("/events/{id}", [EventController::class, 'show']);
    Route::post('/events', [EventController::class, 'create']);
    Route::put('/events/{id}', [EventController::class, 'save']);
    Route::delete('/events/{id}', [EventController::class, 'destroy']);

こちらもカレンダーのルーティングを記述したときと同じ様な内容ですね。
CURLで動作の確認を行ってください。

ルーティングファイルの編集

現在のルーティングファイルは、同じ様な記述が複数あり見にくいので、Group機能を適用します。
api.phpを次の様に編集してください。
※一応全文を載せます。

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\EventController;
use App\Http\Controllers\CalendarController;

Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
    return $request->user();
});

// カレンダー関連
Route::group(['prefix' => 'calendars', 'as' => 'calendars.'], function () {
    Route::get('/', [CalendarController::class, 'index'])->name('index');
    Route::get("/{id}", [CalendarController::class, 'show'])->name('show');
    Route::post('/', [CalendarController::class, 'create'])->name('create');
    Route::put('/{id}', [CalendarController::class, 'save'])->name('update');
    Route::delete('/{id}', [CalendarController::class, 'destroy'])->name('delete');
});

// イベント関連
Route::group(['prefix' => 'events', 'as' => 'events.'], function () {
    Route::get('/', [EventController::class, 'index'])->name('index');
    Route::get("/{id}", [EventController::class, 'show'])->name('show');
    Route::post('/', [EventController::class, 'create'])->name('create');
    Route::put('/{id}', [EventController::class, 'save'])->name('update');
    Route::delete('/{id}', [EventController::class, 'destroy'])->name('delete');
});

Laravelのルーティングには色々な機能があり、全てを紹介はできませんが、私がよく利用する「prefix」と「name」だけ触れておきます。

ルートグループは多くのルートで共通なミドルウェアや名前空間のようなルート属性をルートごとに定義するのではなく、一括して適用するための手法です。Route::groupメソッドの最初の引数には、共通の属性を配列で指定します。 

要は、同じ名前やURLのものを省略できる機能です。
nameについては、正直今回は必要ありませんが、bladeテンプレートなどから呼び出す際にnameに指定した文字列で、ルートを指定できる様になり、記述が簡潔になります。

ルーティングの機能について、もっと知りたい方は下記をご覧ください。

基本的なルーティング

API編②のまとめ

お疲れ様でした!!
API編はこれで終わりです。まだWEBの画面を殆ど開発していないので退屈だったと思います。

次回からフロント編が始まります。
フロントは目で動きが追えるので開発していて、とても楽しいです!!
一緒に頑張りましょう!!次回をお楽しみに!!

Laravelの基礎的な部分を学習する場合、下記の書籍がおすすめです。
環境構築などにもつまづく事がなく、プログラミングを始めたばかりの初学者の方にもおすすめです。

今回作成したコントローラーやルーティング周りについても、易しく解説されています。
この記事で解説を飛ばした部分の穴埋めに是非、読んでみてください!!


こちらの書籍は、かなり詳細にAPIの設計などについて書かれています。
本気でLaravelを習得したい方は、是非手に取ってみてください!

コメントを残す