Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

UUID primary keys cause IRI generation failure in Laravel

已关闭
#8,167 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
35/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
停滞
技术栈
laravel, mariadb, php
领域
api, backend

调研方向

从 vendor/api-platform/laravel/Routing/IriConverter.php 开始,重点查看第 119-125 行附近的 getIriFromResource() 和第 182 行附近的 generateRoute(),然后将报告中的操作元数据和路由名称与显式定义的 ApiResource 操作进行比较。重现 issue 中的集合请求,并验证每栋建筑都能使用基于 UUID 的 IRI 成功完成序列化。

由索引模型根据 Issue 内容生成。

描述

JSON:API Laravel

API Platform version(s) affected: 4.1.20

Description
When using UUID as the primary key for Eloquent models with API Platform Laravel, the IriConverter fails to generate proper IRIs for individual items in collections. This results in a InvalidArgumentException: Unable to generate an IRI for the item of type 'App\Models\Building' error when trying to serialize collections in JSON:API format.

The issue occurs because API Platform generates malformed route names (_api_/api/buildings{._format}_get) that don't match the actual Laravel routes and don't include the UUID parameter.

How to reproduce

  1. Create a Laravel model with UUID as primary key:
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use ApiPlatform\Metadata\Delete;

#[ApiResource(
    operations: [
        new GetCollection(
            uriTemplate: '/buildings',
            name: 'api_buildings_get_collection'
        ),
        new Get(
            uriTemplate: '/buildings/{uuid}',
            name: 'api_buildings_get_item'
        ),
        new Post(
            uriTemplate: '/buildings',
            name: 'api_buildings_post'
        ),
        new Put(
            uriTemplate: '/buildings/{uuid}',
            name: 'api_buildings_put'
        ),
        new Delete(
            uriTemplate: '/buildings/{uuid}',
            name: 'api_buildings_delete'
        )
    ],
    normalizationContext: ['groups' => ['building:read']],
    denormalizationContext: ['groups' => ['building:write']],
    paginationEnabled: true
)]
class Building extends Model
{
    protected $primaryKey = 'uuid';
    protected $keyType = 'string';
    public $incrementing = false;
    
    protected static function boot()
    {
        parent::boot();
        static::creating(function ($model) {
            if (!$model->uuid) {
                $model->uuid = (string) Str::uuid();
            }
        });
    }
}
  1. Create a migration with UUID primary key:
Schema::create('buildings', function (Blueprint $table) {
    $table->uuid('uuid')->primary();
    $table->string('name');
    $table->uuid('user_uuid');
    $table->timestamps();
});
  1. Configure API Platform (config/api-platform.php):
return [
    'formats' => [
        'jsonapi' => ['application/vnd.api+json'],
    ],
    'defaults' => [
        'route_prefix' => '/api',
    ],
];
  1. Make a request to the collection endpoint:
// Test case
public function test_it_lists_buildings(): void
{
    Building::factory()->count(3)->create();
    
    $response = $this->get('/api/buildings', [
        'Accept' => 'application/vnd.api+json',
    ]);
    
    $response->assertOk(); // Fails with IRI generation error
}

Error Output:

InvalidArgumentException: Unable to generate an IRI for the item of type "App\Models\Building"

Stack trace:
#0 vendor/api-platform/laravel/Routing/IriConverter.php(182): Unable to generate an IRI for the item of type "App\Models\Building"
api-platform/api-platform#1 vendor/api-platform/laravel/Routing/IriConverter.php(149): ApiPlatform\Laravel\Routing\IriConverter->generateRoute()
api-platform/api-platform#2 vendor/api-platform/jsonapi/Serializer/ItemNormalizer.php(100): ApiPlatform\Laravel\Routing\IriConverter->getIriFromResource()

Debug logs from IriConverter:

[IriConverter] Generating route:
- routeName: "_api_/api/buildings{._format}_get"
- identifiers: ["uuid" => "550e8400-e29b-41d4-a716-446655440000"]
- operation_class: "ApiPlatform\Metadata\Get"
- operation_name: "_api_/api/buildings{._format}_get"

Possible Solution
The issue appears to be in IriConverter::getIriFromResource() where it creates a new Get operation without proper configuration:

// Line 119-125 in IriConverter.php
if (!$operation) {
    $operation = (new Get())->withClass($resourceClass);
}

This new operation doesn't have the correct route name or URI template. The IriConverter should:

  1. Use the explicitly defined operation names from the ApiResource attribute
  2. Properly detect and handle UUID identifiers
  3. Generate route names that match Laravel's routing conventions

A potential fix would be to ensure the operation metadata is properly loaded from the resource metadata factory before attempting to generate IRIs.

Additional Context

  • Laravel version: 12.x
  • PHP version: 8.4+
  • Database: MariaDB with UUID columns
  • Authentication: Laravel Sanctum

The error occurs specifically when the JSON:API serializer tries to generate the @id field for each item in a collection. Individual item fetches may work if accessed directly, but collections fail during serialization.

This bug prevents any Laravel application using UUIDs as primary keys from working properly with API Platform, which is a significant limitation since UUIDs are commonly used in modern applications for distributed systems and better security.

Workarounds attempted (all failed):

  • Defining explicit operations with names and uriTemplates
  • Using custom State Providers
  • Changing route prefix configurations
  • Testing with different output formats (JSON:API, HAL+JSON)
主要语言
PHP
星标
2.6k
派生
982
平均合并
1 天 21 小时
30 天内合并 PR
67

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

api-platform/core 的其他 Issue

查看 api-platform/core 的全部 Issue

相似的 Issue

更多 PHP Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。