UUID primary keys cause IRI generation failure in Laravel
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 35/100
Línea de trabajo
Comience en vendor/api-platform/laravel/Routing/IriConverter.php, especialmente en getIriFromResource() alrededor de las líneas 119-125 y en generateRoute() alrededor de la línea 182; después, compare los metadatos de operación y los nombres de ruta indicados con las operaciones de ApiResource definidas explícitamente. Reproduzca la solicitud de colección del issue y verifique que la serialización se realiza correctamente con IRIs basados en UUID para cada edificio.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
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
- 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();
}
});
}
}
- 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();
});
- Configure API Platform (
config/api-platform.php):
return [
'formats' => [
'jsonapi' => ['application/vnd.api+json'],
],
'defaults' => [
'route_prefix' => '/api',
],
];
- 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:
- Use the explicitly defined operation names from the ApiResource attribute
- Properly detect and handle UUID identifiers
- 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)
- Lenguaje dominante
- PHP
- Estrellas
- 2.6k
- Forks
- 982
- Merge medio
- 1 d 16 h
- PR fusionados (30 d)
- 59
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de api-platform/core
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 85/100
api-platform/core#8573 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
api-platform/core#8571 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
api-platform/core#8564 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
api-platform/core#8495 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
api-platform/core#8471 ·
Todos los issues de api-platform/core
Issues similares
-
Bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
Automattic/safe-publish#594 ·
-
needs-triage Platform(Default)
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
-
HttpClient
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
symfony/symfony-docs#23092 ·
-
sync-en
Dificultad 1/5 Menos de una hora Aptitud para principiantes 90/100
-
sync-en
Dificultad 1/5 Menos de una hora Aptitud para principiantes 95/100