iT邦幫忙

2025 iThome 鐵人賽

DAY 4
0
Modern Web

Laravel 12 開發者幸福度升級指南系列 第 4

Day 04:使用Junie 生成第一個 CRUD API

  • 分享至 

  • xImage
  •  

引入 Laravel Booth 之後,現在我們可以來開始嘗試撰寫程式了

以前要建立一個商品的 CRUD API,我們需要學習有關路由、migration、控制器等等的觀念,並且自己手刻這些檔案。

現在有了 AI 協助,我們可以更加便利的產生出這些檔案了!

我們在 Junie 的對話框內輸入

我想要寫一個商品的 CRUD API,請幫我生成需要的所有程式

[!NOTE]
每次執行可能結果不會完全相同,但是大致結果會是一樣的

可以看到 Junie 幫我們規劃需要生成的檔案

1. Explore existing codebase for Product-related files to avoid duplication.
2. Implement Product domain:
- Model with casts and fillable
- Migration for products table
- Factory for tests/seeding
3. Build API layer:
- Resource for response shaping
- Form Requests for validation
- Controller with CRUD actions returning proper responses
- API routes and register api routing in bootstrap/app.php
4. Write tests:
- Pest feature tests covering list, create, validate, show, update, delete
5. Run targeted tests:
- Run migrations and then run tests for Product API
6. Fix style with Pint and re-run targeted tests
7. Summarize changes and propose next steps; ask if full test suite should run

接著,比起從 chatGPT 問完之後複製貼上,Junie 已經幫我們生成對應的檔案放好了!

我們來看看 Junie 幫我們生成了哪些檔案,又改了哪些檔案

首先我們看 bootstrap/app.php

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        //
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();

這是 Laravel 12 新的做法,在 bootstrap/app.php 裡面註冊網頁和 API 對應的路由 PHP。這邊 Junie 幫我們新增了 api 的部分。

接著我們看 routes/api.php

<?php

use App\Http\Controllers\ProductController;
use Illuminate\Support\Facades\Route;

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

這邊使用的是 apiResource,能簡潔的生成 API 所需的所有路由,略過網頁建立和修改物件的部分。

我們進去看 ProductController,可以看到對應的程式也已經生成完畢了!

甚至包含到對應的 migration 也都建立好了

<?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('products', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->text('description')->nullable();
            $table->decimal('price', 10, 2);
            $table->unsignedInteger('stock')->default(0);
            $table->boolean('is_active')->default(true);
            $table->timestamps();
        });
    }

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

到這邊可能有些人會躍躍欲試,想著要開啟 Postman 之類的測試工具,趕快來測試一下剛寫好的 API。

這也不用心急!因為在 Laravel Boost 幫我們生成的 guildline 裡面,其實包含了自動化測試的規範

=== pest/core rules ===

## Pest

### Testing
- If you need to verify a feature is working, write or update a Unit / Feature test.

所以即使我們的提示詞裡面沒有提到自動化測試, Junie 也幫我們生成了對應的自動化測試!

<?php

declare(strict_types=1);

use App\Models\Product;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

it('lists products (paginated)', function () {
    Product::factory()->count(3)->create();

    $response = $this->getJson('/api/products');

    $response->assertSuccessful()
        ->assertJsonStructure([
            'data' => [
                '*' => ['id', 'name', 'description', 'price', 'stock', 'is_active', 'created_at', 'updated_at'],
            ],
            'links',
            'meta',
        ]);
});

it('creates a product', function () {
    $payload = [
        'name' => 'iPhone 42',
        'description' => 'The future phone',
        'price' => 1999.99,
        'stock' => 5,
        'is_active' => true,
    ];

    $response = $this->postJson('/api/products', $payload);

    $response->assertCreated();

    $response->assertJsonFragment([
        'name' => 'iPhone 42',
        'description' => 'The future phone',
        'price' => 1999.99,
        'stock' => 5,
        'is_active' => true,
    ]);

    expect(Product::where('name', 'iPhone 42')->exists())->toBeTrue();
});

it('shows a product', function () {
    $product = Product::factory()->create();

    $this->getJson("/api/products/{$product->id}")
        ->assertSuccessful()
        ->assertJsonPath('data.id', $product->id);
});

it('updates a product', function () {
    $product = Product::factory()->create();

    $this->putJson("/api/products/{$product->id}", [
        'name' => 'Updated',
        'price' => 10,
    ])->assertSuccessful()
        ->assertJsonPath('data.name', 'Updated')
        ->assertJsonPath('data.price', 10);
});

it('deletes a product', function () {
    $product = Product::factory()->create();

    $this->deleteJson("/api/products/{$product->id}")
        ->assertNoContent();

    expect(Product::find($product->id))->toBeNull();
});

it('validates store request', function () {
    $this->postJson('/api/products', [
        'price' => -1,
    ])->assertUnprocessable()
        ->assertJsonValidationErrors(['name', 'price']);
});

並且在生成之後,Junie 會先將生成的結果跑過測試,如果沒有全部通過的話會再進行調整。

所以我們可以肯定這段程式是會通過我們的自動化測試的

執行之後的結果如下

 php artisan test

   PASS  Tests\Unit\ExampleTest
  ✓ that true is true                                                                                0.01s  

   PASS  Tests\Feature\Auth\AuthenticationTest
  ✓ login screen can be rendered                                                                     0.20s  
  ✓ users can authenticate using the login screen                                                    0.34s  
  ✓ users can not authenticate with invalid password                                                 0.24s  
  ✓ users can logout                                                                                 0.01s  

   PASS  Tests\Feature\Auth\EmailVerificationTest
  ✓ email verification screen can be rendered                                                        0.02s  
  ✓ email can be verified                                                                            0.01s  
  ✓ email is not verified with invalid hash                                                          0.01s  
  ✓ already verified user visiting verification link is redirected without firing event again        0.01s  

   PASS  Tests\Feature\Auth\PasswordConfirmationTest
  ✓ confirm password screen can be rendered                                                          0.02s  
  ✓ password can be confirmed                                                                        0.02s  
  ✓ password is not confirmed with invalid password                                                  0.22s  

   PASS  Tests\Feature\Auth\PasswordResetTest
  ✓ reset password link screen can be rendered                                                       0.02s  
  ✓ reset password link can be requested                                                             0.22s  
  ✓ reset password screen can be rendered                                                            0.25s  
  ✓ password can be reset with valid token                                                           0.28s  

   PASS  Tests\Feature\Auth\RegistrationTest
  ✓ registration screen can be rendered                                                              0.02s  
  ✓ new users can register                                                                           0.06s  

   PASS  Tests\Feature\DashboardTest
  ✓ guests are redirected to the login page                                                          0.01s  
  ✓ authenticated users can visit the dashboard                                                      0.03s  

   PASS  Tests\Feature\ExampleTest
  ✓ it returns a successful response                                                                 0.01s  

   PASS  Tests\Feature\ProductApiTest
  ✓ it lists products (paginated)                                                                    0.01s  
  ✓ it creates a product                                                                             0.01s  
  ✓ it shows a product                                                                               0.01s  
  ✓ it updates a product                                                                             0.01s  
  ✓ it deletes a product                                                                             0.01s  
  ✓ it validates store request                                                                       0.01s  

   PASS  Tests\Feature\Settings\PasswordUpdateTest
  ✓ password can be updated                                                                          0.05s  
  ✓ correct password must be provided to update password                                             0.04s  

   PASS  Tests\Feature\Settings\ProfileUpdateTest
  ✓ profile page is displayed                                                                        0.03s  
  ✓ profile information can be updated                                                               0.04s  
  ✓ email verification status is unchanged when email address is unchanged                           0.04s  
  ✓ user can delete their account                                                                    0.02s  
  ✓ correct password must be provided to delete account                                              0.03s  

  Tests:    34 passed (116 assertions)
  Duration: 2.39s

到這邊,我們不僅僅程式寫完了,對應的 migration 做好了,甚至還生成了對應的自動化測試檔案,並全部執行通過!

今天的部分就到這邊,我們明天見!


上一篇
Day 03:安裝 Laravel Boost 利用 AI 協助我們開發專案和除錯
系列文
Laravel 12 開發者幸福度升級指南4
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言