← Назад к вопросам

REST API для сущности Item (Laravel)

2.0 Middle🔥 211 комментариев
#API и веб-протоколы#Тестирование#Фреймворки

Условие

Разработать REST API (CRUD) сервис на Laravel для управления сущностью Item.

Структура сущности Item

  • id - целочисленный автоинкремент
  • name - символьное поле (255 символов)
  • key - символьное поле (25 символов, обязательное)
  • created_at - дата создания
  • updated_at - дата обновления

Требования

  • Реализовать CRUD операции (Create, Read, Update, Delete)
  • Валидация входных данных
  • Использовать миграции для создания таблиц
  • Использовать Eloquent-модели
  • Написать автоматические тесты (покрытие 90%)

Технологии

PHP 8+, Laravel 10+, PHPUnit

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Решение

1. Миграция базы данных

Создание таблицы items:

<?php

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

return new class extends Migration {
    public function up(): void {
        Schema::create("items", function (Blueprint $table) {
            $table->id();
            $table->string("name", 255)->nullable();
            $table->string("key", 25)->unique();
            $table->timestamps();
        });
    }

    public function down(): void {
        Schema::dropIfExists("items");
    }
};

2. Eloquent модель

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Item extends Model {
    protected $fillable = ["name", "key"];
    protected $casts = [
        "created_at" => "datetime",
        "updated_at" => "datetime",
    ];
}

3. Form Request для валидации

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreItemRequest extends FormRequest {
    public function authorize(): bool {
        return true;
    }

    public function rules(): array {
        return [
            "name" => "nullable|string|max:255",
            "key" => "required|string|max:25|unique:items,key",
        ];
    }

    public function messages(): array {
        return [
            "key.required" => "Поле key обязательно",
            "key.max" => "Key не может быть длинне 25 символов",
            "key.unique" => "Key уже существует",
            "name.max" => "Name не может быть длинне 255 символов",
        ];
    }
}

class UpdateItemRequest extends FormRequest {
    public function authorize(): bool {
        return true;
    }

    public function rules(): array {
        $itemId = $this->route("item")->id;
        return [
            "name" => "nullable|string|max:255",
            "key" => "sometimes|required|string|max:25|unique:items,key,{$itemId}",
        ];
    }
}

4. REST контроллер

<?php

namespace App\Http\Controllers\Api;

use App\Http\Requests\StoreItemRequest;
use App\Http\Requests\UpdateItemRequest;
use App\Models\Item;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Resources\Json\JsonResource;

class ItemController extends Controller {
    /**
     * GET /api/items - Получить все items
     */
    public function index(): JsonResponse {
        $items = Item::paginate(15);
        return response()->json($items);
    }

    /**
     * POST /api/items - Создать новый item
     */
    public function store(StoreItemRequest $request): JsonResponse {
        $item = Item::create($request->validated());
        return response()->json($item, 201);
    }

    /**
     * GET /api/items/{id} - Получить item по id
     */
    public function show(Item $item): JsonResponse {
        return response()->json($item);
    }

    /**
     * PUT /api/items/{id} - Обновить item
     */
    public function update(UpdateItemRequest $request, Item $item): JsonResponse {
        $item->update($request->validated());
        return response()->json($item);
    }

    /**
     * DELETE /api/items/{id} - Удалить item
     */
    public function destroy(Item $item): JsonResponse {
        $item->delete();
        return response()->json(["message" => "Item deleted successfully"], 200);
    }
}

5. Маршруты API

<?php

use App\Http\Controllers\Api\ItemController;
use Illuminate\Support\Facades\Route;

Route::apiResource("items", ItemController::class);
// Автоматически создаст маршруты для:
// GET /api/items
// POST /api/items
// GET /api/items/{item}
// PUT /api/items/{item}
// DELETE /api/items/{item}

6. Тесты (PHPUnit)

<?php

namespace Tests\Feature;

use App\Models\Item;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class ItemControllerTest extends TestCase {
    use RefreshDatabase;

    public function test_get_all_items(): void {
        Item::factory()->count(3)->create();
        $response = $this->getJson("/api/items");
        $response->assertStatus(200);
        $response->assertJsonCount(3, "data");
    }

    public function test_create_item(): void {
        $data = ["name" => "Test Item", "key" => "test-key"];
        $response = $this->postJson("/api/items", $data);
        $response->assertStatus(201);
        $response->assertJsonPath("name", "Test Item");
        $response->assertJsonPath("key", "test-key");
        $this->assertDatabaseHas("items", $data);
    }

    public function test_create_item_validation_fails(): void {
        $data = ["name" => "Test Item"];
        $response = $this->postJson("/api/items", $data);
        $response->assertStatus(422);
        $response->assertJsonValidationErrors(["key"]);
    }

    public function test_get_item_by_id(): void {
        $item = Item::factory()->create(["key" => "unique-key"]);
        $response = $this->getJson("/api/items/{$item->id}");
        $response->assertStatus(200);
        $response->assertJsonPath("key", "unique-key");
    }

    public function test_update_item(): void {
        $item = Item::factory()->create();
        $newData = ["name" => "Updated", "key" => "updated-key"];
        $response = $this->putJson("/api/items/{$item->id}", $newData);
        $response->assertStatus(200);
        $this->assertDatabaseHas("items", ["id" => $item->id, "name" => "Updated"]);
    }

    public function test_delete_item(): void {
        $item = Item::factory()->create();
        $response = $this->deleteJson("/api/items/{$item->id}");
        $response->assertStatus(200);
        $this->assertDatabaseMissing("items", ["id" => $item->id]);
    }

    public function test_unique_key_validation(): void {
        Item::factory()->create(["key" => "same-key"]);
        $data = ["name" => "Another", "key" => "same-key"];
        $response = $this->postJson("/api/items", $data);
        $response->assertStatus(422);
        $response->assertJsonValidationErrors(["key"]);
    }

    public function test_key_max_length(): void {
        $longKey = str_repeat("a", 26);
        $data = ["key" => $longKey];
        $response = $this->postJson("/api/items", $data);
        $response->assertStatus(422);
    }
}

7. Factory для тестов

<?php

namespace Database\Factories;

use App\Models\Item;
use Illuminate\Database\Eloquent\Factories\Factory;

class ItemFactory extends Factory {
    protected $model = Item::class;

    public function definition(): array {
        return [
            "name" => $this->faker->sentence(),
            "key" => $this->faker->unique()->word(),
        ];
    }
}

Запуск тестов

php artisan test --coverage

API примеры

GET /api/items - Получить все POST /api/items - {"name": "Item", "key": "item-key"} GET /api/items/1 - Получить по id PUT /api/items/1 - Обновить DELETE /api/items/1 - Удалить

REST API для сущности Item (Laravel) | PrepBro