Laravel11の変更点を踏まえてバックエンドAPIを開発する方法まとめ


 

こんにちは。Tomoyuki(@tomoyuki65)です。

以前Laravel10でバックエンドAPI開発をする方法について記事を書きましたが、2024年3月にLaravel11がリリースされたので試してみました。

この記事では以前書いた記事を参考にしつつ試した部分について、変更点を踏まえてAPIを開発する方法をまとめておきます。

 

Laravelの関連記事👇

Laravel10(PHP)でバックエンドAPIを開発する方法まとめ【OpenAPI仕様書・管理画面カスタマイズ】

2023年12月29日

 



Laravel11の変更点を踏まえてバックエンドAPIを開発する方法まとめ

まずは以下のコマンドを実行し、プロジェクトの作成を行います。

$ mkdir laravel11
$ cd laravel11
$ curl -s "https://laravel.build/api?with=mysql"| bash

※ディレクトリ名はapiとし、不要なものはインストールさせないようmysqlだけ指定しています。尚、コマンド実行にはDockerを使える必要があるため、まだの方は事前にご準備下さい。

 

最後にOSなどに設定しているパスワードを聞かれるので、入力して完了させて下さい。

 

パスワード入力後、以下のようにプロジェクトが作成されれば完了です。

 

環境変数ファイル「.env」を修正

次に環境変数用のファイル「.env」を次のように修正します。

・・・

APP_TIMEZONE=Asia/Tokyo

・・・

APP_LOCALE=ja
APP_FALLBACK_LOCALE=ja
APP_FAKER_LOCALE=ja_JP

・・・

APP_MAINTENANCE_STORE=file

・・・

DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=l11_db
DB_USERNAME=l11_user
DB_PASSWORD=l11_password
DB_COLLATION=utf8mb4_bin

SESSION_DRIVER=file

・・・

QUEUE_CONNECTION=sync

CACHE_STORE=file

・・・

 

次に以下のコマンドを実行し、テストDB用の環境変数ファイル「.env.testing」を作成します。

$ cp .env .env.testing

 

次に作成したファイル「.env.testing」について、以下の項目をテスト用に修正します。

・・・

APP_KEY=

・・・

DB_CONNECTION=mysql_test
DB_HOST=db_test
DB_PORT=3307
DB_DATABASE=l11_db_test
DB_USERNAME=l11_user_test
DB_PASSWORD=l11_password_test
DB_COLLATION=utf8mb4_bin

・・・

 

DBの接続設定を修正

次にDBの接続設定を修正するため、ファイル「api/config/database.php」を以下のように修正します。

・・・

    'connections' => [

        ・・・

        'mysql' => [
            'driver' => 'mysql',
            'url' => env('DB_URL'),
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'laravel'),
            'username' => env('DB_USERNAME', 'root'),
            'password' => env('DB_PASSWORD', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => env('DB_CHARSET', 'utf8mb4'),
            'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
            ]) : [],
        ],

        // テスト用DB
        'mysql_test' => [
            'driver' => 'mysql',
            'url' => env('DB_URL'),
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3307'),
            'database' => env('DB_DATABASE', 'laravel'),
            'username' => env('DB_USERNAME', 'root'),
            'password' => env('DB_PASSWORD', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => env('DB_CHARSET', 'utf8mb4'),
            'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
            ]) : [],
        ],

・・・

 

次にテスト実行用としてファイル「api/phpunit.xml」に「<env name=”DB_CONNECTION” value=”mysql_test”/>」を追加し、DB_DATABASE設定を「<env name=”DB_DATABASE” value=”l11_db_test”/>」に修正します。

・・・
    
   <php>
        <env name="APP_ENV" value="testing"/>
        <env name="APP_MAINTENANCE_DRIVER" value="file"/>
        <env name="BCRYPT_ROUNDS" value="4"/>
        <env name="CACHE_STORE" value="array"/>
        <env name="DB_CONNECTION" value="mysql_test"/>
        <env name="DB_DATABASE" value="l11_db_test"/>
        <env name="MAIL_MAILER" value="array"/>
        <env name="PULSE_ENABLED" value="false"/>
        <env name="QUEUE_CONNECTION" value="sync"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="TELESCOPE_ENABLED" value="false"/>
    </php>

・・・

 



独自のDocker環境を構築

次にLaravel11ではsailコマンドでDocker環境を構築できますが、実務を考慮して独自のDocker環境を構築するため、まずは以下のコマンドを実行して「docker-compose.yml」のファイル名を修正します。

$ mv docker-compose.yml docker-compose.sail.yml

 

次に以下のコマンドを実行し、各種ディレクトリやファイルを作成します。

$ touch compose.yml
$ mkdir docker
$ cd docker
$ mkdir local
$ cd local
$ mkdir php
$ mkdir mysql
$ cd mysql
$ touch my.cnf
$ cd ../php
$ touch Dockerfile
$ touch 000-default.conf
$ touch php.ini
$ cd ../../..

 

次に作成した各種ファイルについて、下記のようにそれぞれ記述します。

services:
  api:
    build:
      context: .
      dockerfile: ./docker/local/php/Dockerfile
      container_name: api
    volumes:
      - .:/app
    ports:
      - '80:8080'
    depends_on:
      - db
      - db_test
  db:
    image: mysql:8.0.36
    container_name: db
    environment:
      MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
      MYSQL_ROOT_HOST: "%"
      MYSQL_DATABASE: '${DB_DATABASE}'
      MYSQL_USER: '${DB_USERNAME}'
      MYSQL_PASSWORD: '${DB_PASSWORD}'
      MYSQL_ALLOW_EMPTY_PASSWORD: 1
      TZ: 'Asia/Tokyo'
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_bin
    volumes:
      - db-data:/var/lib/mysql
      - ./docker/local/mysql/my.cnf:/etc/mysql/conf.d/my.cnf
    ports:
      - 3306:3306
  db_test:
    image: mysql:8.0.36
    container_name: db_test
    environment:
      MYSQL_ROOT_PASSWORD: 'l11_user_password'
      MYSQL_ROOT_HOST: "%"
      MYSQL_DATABASE: 'l11_db_test'
      MYSQL_USER: 'l11_user_test'
      MYSQL_PASSWORD: 'l11_user_password'
      MYSQL_TCP_PORT: 3307
      MYSQL_ALLOW_EMPTY_PASSWORD: 1
      TZ: 'Asia/Tokyo'
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_bin
    volumes:
      - ./docker/local/mysql/my.cnf:/etc/mysql/conf.d/my.cnf
    tmpfs:
      - /var/lib/mysql
    ports:
      - 3307:3307
    expose:
      - 3307
volumes:
  db-data:
    driver: local

 

[Date]
date.timezone = "Asia/Tokyo"

[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_bin

[client]
default-character-set=utf8mb4

 

FROM php:8.3-apache

ENV COMPOSER_ALLOW_SUPERUSER 1
ENV COMPOSER_NO_INTERACTION 1
ENV COMPOSER_HOME /composer

WORKDIR /app

RUN apt-get update && apt-get install -y \
    libzip-dev \
    && docker-php-ext-install zip pdo_mysql

COPY --from=composer /usr/bin/composer /usr/bin/composer

COPY . /app
COPY ./docker/local/php/php.ini /usr/local/etc/php/php.ini
COPY ./docker/local/php/000-default.conf /etc/apache2/sites-available/000-default.conf

RUN composer install

RUN chmod 777 -R storage && \
echo "Listen 8080" >> /etc/apache2/ports.conf && \
a2enmod rewrite

CMD ["apache2-foreground"]

 

<VirtualHost *:8080>
  ServerAdmin webmaster@localhost
  DocumentRoot /app/public/

  <Directory /app/>
    AllowOverride All
    Require all granted
  </Directory>

  ErrorLog ${APACHE_LOG_DIR}/error.log
  CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

 

zend.exception_ignore_args = off
expose_php = on
max_execution_time = 30
max_input_vars = 1000
upload_max_filesize = 64M
post_max_size = 128M
memory_limit = 256M
error_reporting = E_ALL
display_errors = on
display_startup_errors = on
log_errors = on
error_log = /var/log/php/php-error.log
default_charset = UTF-8

[Date]
date.timezone = Asia/Tokyo

[mysqlnd]
mysqlnd.collect_memory_statistics = on

[Assertion]
zend.assertions = 1

[mbstring]
mbstring.language = Japanese

※000-default.confやphp.iniは開発用の設定です。もし本番環境で使う際はカスタマイズして下さい。

 

次に以下のコマンドを実行し、コンテナのビルドと起動を行います。

$ docker compose build --no-cache
$ docker compose up -d

 

次にブラウザで「http://localhost」にアクセスし、下図のように表示されればOKです。

 



テスト用環境変数ファイル「.env.testing」のアプリケーションキーを設定

次に以下のコマンドを実行し、テスト用の環境変数ファイル「.env.testing」のAPP_KEYを設定します。

$ docker compose exec api php artisan key:generate --env=testing

 

マイグレーションファイルの再作成

次に既に作成されているマイグレーションファイルを全て削除し、以下のコマンドを実行して新しいユーザーテーブル用のマイグレーションファイルを作成します。

$ docker compose exec api php artisan make:migration create_users_table

 

そして、新しく作成したマイグレーションファイルの中身は次のように修正します。

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
    * Run the migrations.
    */
    public function up(): void
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('uid')->unique();
            $table->integer('member_id')->unique()->nullable();;
            $table->string('last_name');
            $table->string('first_name');
            $table->string('email')->unique();
            $table->datetimes();
            $table->softDeletesDatetime();
            $table->unique(['email', 'deleted_at'], 'unique_email_deleted_at');
        });
    }

    /**
    * Reverse the migrations.
    */
    public function down(): void
    {
        Schema::dropIfExists('users');
    }
};

 

既存のUserモデルの修正

次は既に作成済みのUserモデルを以下のように修正します。

<?php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\SoftDeletes;

class User extends Authenticatable
{
    use HasFactory, Notifiable, SoftDeletes;

    // 日付フォーマットをY-m-d H:i:sに変更
    protected function serializeDate(\DateTimeInterface $date)
    {
        return $date->format('Y-m-d H:i:s');
    }

    protected $guarded = ['created_at', 'updated_at'];
}

※ユーザーテーブルについて、実務では論理削除するのが基本になると思うので、その場合は「SoftDeletes」を使います。

 

API用のルーティングファイルを公開

Laravel11からAPI用のルーティングファイルが非公開になっているため、以下のコマンドを実行して公開します。

$ docker compose exec api php artisan install:api

 

コマンド実行後、最後に下図のようにマイグレーションを実行するか聞かれますが、noを入力してキャンセルし、追加されたマイグレーションファイルは今回は使わないので削除します。

 



リポジトリパターンでAPIを作成する

次にリポジトリパターンでAPIを作成するため、以下のコマンドを実行して各種ファイルを作成します。

$ mkdir -p app/Repositories/User
$ mkdir -p app/Services
$ touch app/Repositories/User/UserRepository.php
$ touch app/Repositories/User/UserRepositoryInterface.php
$ touch app/Services/UserService.php

 

次に作成したファイルの中身は以下のように記述します。

<?php

namespace App\Repositories\User;

use App\Models\User;

interface UserRepositoryInterface
{
    public function createUser(string $uid, string $last_name, string $first_name, string $email);
    public function saveUser(User $user);
    public function getAllUserWithTrashed();
    public function getUserFromUid(string $uid);
    public function deleteUser(User $user);
}

 

<?php

namespace App\Repositories\User;

use App\Models\User;

class UserRepository implements UserRepositoryInterface
{
    public function createUser(
        string $uid,
        string $last_name,
        string $first_name,
        string $email
    )
    {
        $user = new User();
        $user->uid = $uid;
        $user->last_name = $last_name;
        $user->first_name = $first_name;
        $user->email = $email;

        return $user;
    }

    public function saveUser(User $user)
    {
        $user->save();

        return $user;
    }

    public function getAllUserWithTrashed()
    {
        // 論理削除データも取得
        return User::withTrashed()->get();
    }

    public function getUserFromUid(string $uid)
    {
        return User::where('uid', $uid)->first();
    }

    public function deleteUser(User $user)
    {
        return $user->delete();
    }
}

 

<?php

namespace App\Services;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Repositories\User\UserRepositoryInterface as UserRepository;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Http\Exceptions\HttpResponseException;
use \Symfony\Component\HttpFoundation\Response;

class UserService extends Controller
{
    public function __construct(UserRepository $userRepo)
    {
        $this->userRepositry = $userRepo;
    }

    public function createUser(Request $request)
    {
        try {
            DB::beginTransaction();

            $user = $this->userRepositry->createUser(
                        $request->uid,
                        $request->last_name,
                        $request->first_name,
                        $request->email
                    );

            $user = $this->userRepositry->saveUser($user);

            # 会員IDの設定(9桁)
            $user->member_id = $user->id + 100000000;

            $this->userRepositry->saveUser($user);

            DB::commit();
        } catch (\Exception $e) {
            DB::rollback();
            Log::error("UserService/createUserでエラー");
            throw new HttpResponseException(response()->json(['message' => 'Internal Server Error'], Response::HTTP_INTERNAL_SERVER_ERROR));
        }

        return response()->json(['message' => 'OK'], Response::HTTP_CREATED);
    }

    public function getUsers(Request $request)
    {
        try {

            $users = $this->userRepositry->getAllUserWithTrashed();

        } catch (\Exception $e) {
            Log::error("UserService/getUsersでエラー");
            throw new HttpResponseException(response()->json(['message' => 'Internal Server Error'], Response::HTTP_INTERNAL_SERVER_ERROR));
        }

        return $this->jsonResponse($users);
    }

    public function getUser(Request $request, string $uid)
    {
        try {

            $user = $this->userRepositry->getUserFromUid($uid);

        } catch (\Exception $e) {
            Log::error("UserService/getUserでエラー");
            throw new HttpResponseException(response()->json(['message' => 'Internal Server Error'], Response::HTTP_INTERNAL_SERVER_ERROR));
        }

        return $this->jsonResponse($user);
    }

    public function updateUser(Request $request, string $uid)
    {
        try {
            DB::beginTransaction();

            $user = $this->userRepositry->getUserFromUid($uid);

            if (!is_null($request->name)) {
                $user->name = $request->name;
            }

            if (!is_null($request->email)) {
                $user->email = $request->email;
            }

            $this->userRepositry->saveUser($user);

            DB::commit();
        } catch (\Exception $e) {
            DB::rollback();
            Log::error("UserService/updateUserでエラー");
            throw new HttpResponseException(response()->json(['message' => 'Internal Server Error'], Response::HTTP_INTERNAL_SERVER_ERROR));
        }

        return response()->json(['message' => 'OK']);
    }

    public function destroyUser(Request $request, string $uid)
    {
        try {
            DB::beginTransaction();

            $user = $this->userRepositry->getUserFromUid($uid);

            $this->userRepositry->deleteUser($user);

            DB::commit();
        } catch (\Exception $e) {
            DB::rollback();
            Log::error("UserService/destroyUserでエラー");
            throw new HttpResponseException(response()->json(['message' => 'Internal Server Error'], Response::HTTP_INTERNAL_SERVER_ERROR));
        }

        return response()->json(['message' => 'OK']);
    }
}

 

次にjson出力時の日本語の文字化け対応をするため、共通処理として「api/app/Http/Controllers/Controller.php」に関数「jsonResponse」を追加して使えるようにしておきます。

<?php

namespace App\Http\Controllers;

abstract class Controller
{
    public function jsonResponse($data, $code = 200)
    {
        return response()->json(
                   $data,
                   $code,
                   ['Content-Type' => 'application/json;charset=UTF-8', 'Charset' => 'utf-8'],
                   JSON_UNESCAPED_UNICODE
               );
    }
}

※Laravel11からController.phpにあった「use Illuminate\Foundation\Auth\Access\AuthorizesRequests;」、「use Illuminate\Foundation\Validation\ValidatesRequests;」、「use Illuminate\Routing\Controller as BaseController;」が削除されました。abstract classに変わっているので直接インスタンス化できないのと、「AuthorizesRequests」や「ValidatesRequests」を使いたい場合は、基本的には個別にコントローラーでuseする形になったようです。

 

次に作成したサービスとリポジトリを使えるようにするため、「AppServiceProvider.php」の「register()」の部分に登録します。

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
    * Register any application services.
    */
    public function register(): void
    {
        $this->app->bind('App\Services\UserService');
        $this->app->bind('App\Repositories\User\UserRepositoryInterface', 'App\Repositories\User\UserRepository');
    }

    /**
    * Bootstrap any application services.
    */
    public function boot(): void
    {
        //
    }
}

 

ユーザーコントローラーの作成

次に以下のコマンドを実行し、ユーザーコントローラーを作成します。

$ docker compose exec api php artisan make:controller Api/UserController

 

次にユーザーコントローラーの中身は次のように記述します。

※リポジトリパターンでは業務ロジックはサービスに寄せるため、コントローラーはスッキリした記述になります。

<?php

namespace App\Http\Controllers\Api;

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

class UserController extends Controller
{
    public function __construct(UserService $userService)
    {
        $this->userService = $userService;
    }

    public function create(Request $request)
    {
        return $this->userService->createUser($request);
    }

    public function users(Request $request)
    {
        return $this->userService->getUsers($request);
    }

    public function user(Request $request, string $uid)
    {
        return $this->userService->getUser($request, $uid);
    }

    public function update(Request $request, string $uid)
    {
        return $this->userService->updateUser($request, $uid);
    }

    public function delete(Request $request, string $uid)
    {
        return $this->userService->destroyUser($request, $uid);
    }
}

 

ルーティングの追加

次にユーザーコントローラーのルーティングを追加するため、「routes/api.php」を以下のように修正します。

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Api\UserController;

// 今回は不要なのでコメントアウト
// Route::get('/user', function (Request $request) {
// return $request->user();
// })->middleware('auth:sanctum');

Route::prefix('v1')->group(function() {
    Route::post('/user', [UserController::class, 'create']);
    Route::get('/users', [UserController::class, 'users']);
    Route::get('/user/{uid}', [UserController::class, 'user']);
    Route::put('/user/{uid}', [UserController::class, 'update']);
    Route::delete('/user/{uid}', [UserController::class, 'delete']);
});

 

PostmanでAPIの動作確認

次にPostmanでAPIの動作確認をします。(細かい部分は割愛させていただきます。)

まずはユーザー作成のAPIを実行し、下図のように正常終了すればOKです。

 

次にユーザー取得APIを実行し、下図のように対象のユーザーを取得できればOKです。

 

次にユーザー情報更新APIを実行し、下図のように正常終了すればOKです。

 

次にもう一度ユーザー取得APIを実行し、ユーザー情報が更新されていればOKです。

 

次にユーザー削除APIを実行し、下図のように正常終了すればOKです。

 

次にもう一度ユーザー取得APIを実行し、下図のようにデータが取得できなければOKです。

 

次に全てのユーザー取得APIを実行し、対象ユーザーが表示されればOKです。

 



デフォルトでAuthServiceProviderが無い場合の認証機能の追加について

Laravel10では認証機能の処理は「api/app/Providers/AuthServiceProvider.php」に追加しましたが、Laravel11ではデフォルトでこのファイルが存在しません。

Laravel11ではデフォルトで「api/app/Providers/AppServiceProvider.php」しかありませんが、このファイルに認証機能を追加しても同様に認証機能を動作させることができました。

<?php

namespaceApp\Providers;

use Illuminate\Support\ServiceProvider;

// Firebaseの認証機能用
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use Illuminate\Http\Exceptions\HttpResponseException;
use \Symfony\Component\HttpFoundation\Response;
use Kreait\Firebase\Contract\Authas FirebaseAuth;
use App\Models\User;

classAppServiceProviderextendsServiceProvider
{

・・・
    /**
    * Bootstrap any application services.
    */
    public function boot(): void
    {
        // Firebaseによる認証
        Auth::viaRequest('firebase', function (Request $request) {
            $idToken = $request->header('Authorization');
            if (empty($idToken)) {
                throw new HttpResponseException(response()->json(['message' => 'Bad Request'], Response::HTTP_BAD_REQUEST));
            }

            $idToken = str_replace('Bearer ', '', $idToken);
            $firebaseAuth = app(FirebaseAuth::class);
            try {
                $verifiedIdToken = $firebaseAuth->verifyIdToken($idToken);
            } catch (\Exception $e) {
                throw new HttpResponseException(response()->json(['message' => 'Unauthorized'], Response::HTTP_UNAUTHORIZED));
            }

            $uid = $verifiedIdToken->claims()->get('sub');
            $email = $verifiedIdToken->claims()->get('email');

            // DBからユーザー情報取得(論理削除データも含む)
            $user = User::withTrashed()->where('uid', $uid)->first();

            if (!empty($user->deleted_at)) {
                throw new HttpResponseException(response()->json(['message' => 'Bad Request'], Response::HTTP_BAD_REQUEST));
            }

            if (empty($user)) {
                $user = new User();
                $user->uid = $uid;
                $user->email = $email;
            }

            return $user;
        });
    }
}

※boot()の部分に追加したらLaravel10の時と同様に動作させることができました。

 

テストフレームワーク「Pest」の追加について

今回の方法ではデフォルトのテストフレームワークとして「PHPUnit 」がインストールされていますが、「Pest」を導入することも可能です。

ただし、2024年5月時点ではバージョンの兼ね合いでライブラリのインストールにエラーがでたので、Pestを導入したい場合はPHPUnitのバージョンのダウングレードが必要です。

PHPUnitをダウングレードしたい場合は、「api/composer.json」のphpunit/phpunitのバージョンを「10.5.17」に修正して下さい。

・・・

    "require-dev": {
        "fakerphp/faker": "^1.23",
        "laravel/pint": "^1.13",
        "laravel/sail": "^1.26",
        "mockery/mockery": "^1.6",
        "nunomaduro/collision": "^8.0",
        "pestphp/pest-plugin-laravel": "^2.4",
        "phpunit/phpunit": "10.5.17",
        "spatie/laravel-ignition": "^2.4"
    },

・・・

 

修正後、以下のコマンドを実行して更新します。

$ docker compose exec api composer update

 

次に以下のコマンドを実行し、Pestのインストールと初期化を行います。

$ docker compose exec api composer require pestphp/pest-plugin-laravel --dev
$ docker compose exec api ./vendor/bin/pest --init

 

初期化の際に聞かれる質問については「no」を入力して進めればOKです。

 

これで設定用ファイル「api/tests/Pest.php」が作成されるので、「Illuminate\Foundation\Testing\RefreshDatabase::class,」部分のコメントアウトを外し、テスト実行後にDBをリフレッシュさせる設定を有効にしておきます。

・・・

uses(
    Tests\TestCase::class,
    Illuminate\Foundation\Testing\RefreshDatabase::class,
)->in('Feature');

・・・

 

次に以下のコマンドを実行し、テストを実行してみます。

$ docker compose exec api php artisan test

 

テスト実行後、既にあるサンプルファイルのテストが正常終了すればOKです。

 

次に以下のコマンドを実行し、ユーザーAPI用のテストファイルを作成します。

$ docker compose exec api php artisan pest:test UserTest

 

次に作成したファイルの中身を次のように記述します。

<?php

use Illuminate\Support\Str;
use App\Models\User;

test('ユーザーが新規作成され、ステータス201で正常終了すること', function () {
    // API実行
    $path = "/api/v1/user";
    $uid = Str::random(10);
    $last_name = "test";
    $first_name = "taro";
    $email = "test-taro@example.com";
    $body = [
        'uid' => $uid,
        'last_name' => $last_name,
        'first_name' => $first_name,
        'email' => $email
    ];
    $response = $this->post($path, $body);

    // 検証
    expect($response->status())->toBe(201);
    $this->assertDatabaseHas(User::class, [
        'uid' => $uid,
        'last_name' => $last_name,
        'first_name' => $first_name,
        'email' => $email,
    ]);
});

 

テストを実行し、以下のように全てのテストがpassすればOKです。

 



最後に

今回はLaravel11でのAPI開発方法についてまとめました。

Laravel10と比べるとファイル数が減ってスッキリしているので、以前よりもシンプルに開発を始められるのが良さそうです。

もちろん変わっている部分もありますが、基本的には以前と同様に開発を進められるので、少しキャッチアップすれば問題なさそうです。

そんな感じで、これからLaravel11を使う方はぜひ参考にしてみて下さい。

 

各種SNSなど

各種SNSなど、チャンネル登録やフォローをしていただけると励みになるので、よければぜひお願いします!

 

The following two tabs change content below.

Tomoyuki

SEを5年経験後、全くの未経験ながら思い切ってブロガーに転身し、月間13万PVを達成。その後コロナの影響も受け、以前から興味があったWeb系エンジニアへのキャリアチェンジを決意。現在はWeb系エンジニアとして働きながら、プロゲーマーとしても活躍できるように活動中。








シェアはこちらから


【2024年】おすすめのゲーミングPC

モンハンワイルズの発売日とPC版(Steam版)の推薦スペックが公開されたので、おすすめのゲーミングPCをご紹介!


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です