Laravel Eloquentは、データベースとの対話を楽にしてくれる仕組みです。テーブルと対話するモデルを提供することでデータベースの複雑さを簡略化する、オブジェクト関係マッピング(ORM)です。

Laravel Eloquentには、開発をサポートするAPIを作成しテストする優れた機能があります。今回の記事では、Laravelを使用して簡単にAPIを作成し、テストする方法をご紹介します。

このデモでは、まずAPIとデータベーステーブルを構築するためのモデルを作成します。次に、ビジネスロジックの層としてコントローラを追加し、APIを完成させるためのルートを追加する方法を説明します。その後、Postmanを使用してAPIをテストする方法を確認し、最後に認証とエラー処理に焦点を当てます。

前提条件

はじめに、必要なものは以下の通りです。

APIの基礎知識

まずはcomposerでLaravelのプロジェクトを新規作成します。

composer create-project laravel/laravel laravel-api-create-test

サーバーを起動するには、以下のコマンドを実行し、ポート8000でアプリケーションサーバーを実行します。

cd laravel-api-create-test
php artisan serve

以下の画面が表示されるはずです。

Laravel
Laravel

次に、以下のコードで-mフラグを付してマイグレーションのモデルを作成します。

php artisan make:model Product -m

次に、必須フィールドを含むようにマイグレーションファイルをアップグレードします。database/migrations/{date_stamp}_create_products_table.phpファイル内に、商品モデルのタイトルと説明フィールド、および以下の2つのテーブルフィールドを追加します。

$table->string('title');
$table->longText('description');

次に、フィールドを入力可能にしましょう。app/Models/Product.phpの中で、titledescriptionを入力可能なフィールドとして定義します。

protected $fillable = ['title', 'description'];

コントローラの作成

次に、以下のコマンドを実行し、商品のコントローラファイルを作成します。これで、app/Http/Controllers/Api/ProductController.phpファイルが作成されます。

php artisan make:controller ApiProductController --model=Product

そして、商品の作成と取得のためのロジックを追加します。indexメソッドの中に、以下のコードを追加して、すべての商品を取得します。

$products = Product::all();
return response()->json([
    'status' => true,
    'products' => $products
]);

その後、新しい商品をデータベースに保存するためにStoreProductRequestクラスを追加します。同じファイルの一番上に次のクラスを追加してください。

public function store(StoreProductRequest $request)
 {
    $product = Product::create($request->all());

    return response()->json([
        'status' => true,
        'message' => "Product Created successfully!",
        'product' => $product
    ], 200);
 }

続いて、リクエストを作成します。これは以下のコマンドで実行できます。

php artisan make:request StoreProductRequest

バリデーションを追加したい場合は、app/Http/Requests/StoreProductRequest.phpファイルを使用します。このデモでは、バリデーションは実装しません。

ルートを作成する

APIをテストする前の最後のステップとして、ルートを追加します。routes/api.phpファイル内に以下のコードを追加します。ファイルの冒頭にuseを、本文にRouteを追加します。

use AppHttpControllersApiProductController;
Route::apiResource('products', ProductController::class);

APIのテストを開始する前に、productsテーブルがデータベースに存在することを確認してください。存在しない場合は、XAMPPのようなコントロールパネルを使って作成します。また、以下のコマンドで、データベースのマイグレーションも可能です。

php artisan migrate

APIをテストする

APIをテストする前に、app/Http/Requests/StoreProductRequest.php内のauthorizeメソッドがtrueを返すように設定されていることを確認して下さい。

これで、Postmanを使って新しい商品を作ることができます。まず、URL「http://127.0.0.1:8000/api/products/」に対してPOSTリクエストを出します。これは新しい商品を作るためのPOSTリクエストですので、タイトルと説明を記述したJSONオブジェクトを渡します。

{
    "title":"Apple",
    "description":"Best Apples of the world"
}
Postmanで新しい商品を作成する
Postmanで新しい商品を作成する

Send」ボタンをクリックすると、以下のように表示されるはずです。

「Send」ボタンをクリックした後
「Send」ボタンをクリックした後

続いて、GETリクエストを使用して、作成した商品を取得します。URLは同じです。結果は以下のようになります。

GETリクエストで取得した商品
GETリクエストで取得した商品

Sanctumを使用してAPIを認証する

APIを保護する上で、認証は非常に重要です。LaravelではミドルウェアとしてSanctumトークンを使用できます。ユーザーが正しい認証情報を使ってログインすると、トークンが生成され、これを使うことでAPIを保護します。トークンなしでは保護の適用されたAPIにアクセスできません。

認証を実装する最初のステップとして、以下のコードを使用してSanctumパッケージを追加します。

composer require laravel/sanctum

そして、Sanctumの設定ファイルを公開します。

php artisan vendor:publish --provider="LaravelSanctumSanctumServiceProvider"

その後、ミドルウェアとしてSanctumのトークンを追加します。app/Http/Kernel.phpファイル内で、以下のクラスを使用し、保護対象のミドルウェアグループのAPIで、middlewareGroupsを以下のコードに置き換えます。

use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;
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' => [
        EnsureFrontendRequestsAreStateful::class,
        'throttle:api',
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
];

次に、UserControllerを作成し、トークンを取得するコードを追加します。

php artisan make:controller UserController

UserControllerを作成したら、app/Http/Controllers/UserController.phpファイルに移動して、既存のコードを次のコードに置き換えます。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
class UserController extends Controller
{
    // 

    function index(Request $request)
    {
        $user= User::where('email', $request->email)->first();
        // print_r($data);
            if (!$user || !Hash::check($request->password, $user->password)) {
                return response([
                    'message' => ['These credentials do not match our records.']
                ], 404);
            }
        
             $token = $user->createToken('my-app-token')->plainTextToken;
        
            $response = [
                'user' => $user,
                'token' => $token
            ];
        
             return response($response, 201);
    }
}

認証をテストする前に、シーダーでユーザーを採用します。次のコマンドで、UsersTableSeederファイルを作成します。

php artisan make:seeder UsersTableSeeder

database/seeders/UsersTableSeeder.phpファイルの中で、既存のコードを次のコードに置き換えて、シーディングによりユーザーを作成します。

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;

class UsersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        DB::table('users')->insert([
            'name' => 'John Doe',
            'email' => '[email protected]',
            'password' => Hash::make('password')
        ]);
    }
}

次に、このコマンドを使用してシーダーを実行します。

php artisan db:seed --class=UsersTableSeeder

認証フローの最後のステップとして、作成したミドルウェアを使用してルートを保護します。routes/api.phpファイルに移動して、ミドルウェアの中にproductsルートを追加します。

use App\Http\Controllers\UserController;

Route::group(['middleware' => 'auth:sanctum'], function () {
    Route::apiResource('products', ProductController::class);
});

Route::post("login",[UserController::class,'index']);

ミドルウェアにルートを追加した後、商品をフェッチしようとすると次のように内部サーバーエラーが発生します。

ルートを追加した後の内部サーバーエラー
ルートを追加した後の内部サーバーエラー

ログインしてトークンを取得し、それをヘッダーに使用すれば、認証され、動作が開始します。http://127.0.0.1:8000/api/loginに以下のようなボディでPOSTリクエストを送信します。

{
    "email":"[email protected]",
    "password":"password"
}
認証に成功
認証に成功

受け取ったトークンをBearerトークンとして使用し、これをAuthorizationヘッダとして追加します。

BearerトークンをAuthorizationヘッダとして追加
BearerトークンをAuthorizationヘッダとして追加

APIエラーの処理

サーバーにリクエストを送信するとレスポンスが返ってきます。レスポンスと同時に、レスポンスの性質に応じたステータスコードも送信されます。例えば、200のステータスコードはリクエストが成功したことを示し、404はリクエストされたリソースがサーバーに見つからないことを意味します。

しかし、ステータスコードだけでは十分ではありません。人間が読めるようなエラーメッセージが必要です。Laravelには、エラーを処理する多くの機能が用意されています。try-catchブロック、fallbackメソッドを使用したり、カスタムレスポンスを送信したりすることができます。UserControllerの次のコードがこれを処理しています。

if (!$user || !Hash::check($request->password, $user->password)) {
    return response([
        'message' => ['These credentials do not match our records.']
    ], 404);
}

まとめ

LaravelのEloquentにより、APIを簡単に作成、検証、テストできます。オブジェクト関係マッピングのおかげで、データベースとのやり取りが簡単に行えます。

さらに、ミドルウェアとして機能するLaravelのSanctumトークンは、APIを素早く保護するのに役立ちます。

さらなる最適化をお求めであれば、Kinstaのデータベースホスティングソリューションがおすすめです。すべてのウェブプロジェクトのデータベースのセットアップと管理を簡素化する選択肢となっています。

Jeremy Holcombe Kinsta

Kinstaのコンテンツ&マーケティングエディター、WordPress開発者、コンテンツライター。WordPress以外の趣味は、ビーチでのんびりすること、ゴルフ、映画。高身長が特徴。