core icon indicating copy to clipboard operation
core copied to clipboard

Error with Laravel and DTO

Open noweh opened this issue 1 year ago • 1 comments

API Platform version(s) affected: api-platform/laravel 4.0.3

Description
When attempting to use Data Transfer Objects (DTOs) with Laravel, as described in the documentation, I encounter a 404 error on the newly added route:

{
  "@context": "/api/contexts/Error",
  "@id": "/api/errors/404.jsonld",
  "@type": "hydra:Error",
  "trace": [
    {
      "file": "XXXX\\project\\vendor\\api-platform\\laravel\\State\\SwaggerUiProvider.php",
      "line": 57,
      "function": "provide",
      "class": "ApiPlatform\\State\\Provider\\ReadProvider",
      "type": "->"
    },
   ....
}

How to reproduce

  1. Create a DTO resource class:
<?php

namespace App\ApiResource;

use ApiPlatform\Metadata\Get;
use App\State\CatProvider;

#[Get(uriTemplate: '/cats/{id}', provider: CatProvider::class)]
class Cat
{
    public string $id;
    public string $name;
    public int $age;
}
  1. Configure api-platform.php to include the DTO resource path:
// config/api-platform.php

// ...
return [
    'resources' => [
        app_path('ApiResource'),
        app_path('Models'),
    ],

    // ...
];
  1. Implement the CatProvider class that fetches data from the model:
<?php

namespace App\State;

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\Models\Animal as AnimalModel;

final class CatProvider implements ProviderInterface
{
    public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
    {
        $animal = AnimalModel::find($uriVariables['id']);

        return new AnimalModel([
            'id' => $animal->id,
            'name' => $animal->name,
            'age' => $animal->age
        ]);
    }
}
  1. Register the provider in the AppServiceProvider:
<?php

namespace App\Providers;

use App\State\CatProvider;
use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\Foundation\Application;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        $this->app->singleton(CatProvider::class, function (Application $app) {
            return new CatProvider();
        });

        $this->app->tag([CatProvider::class], 'provider');
    }

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

Expected Behavior The GET /cats/{id} route should return the correct data for the Cat resource using the CatProvider.

noweh avatar Oct 12 '24 17:10 noweh

@noweh Thanks for your report.

There is an error in the following documentation. You need in your CatProvider to return the DTO ApiResource/Cat.php and not the model Models/Animal.php.

However, if you still want to do this you need to add the $fillable property to your Dto, like this:

<?php

namespace App\Models;

use ApiPlatform\Metadata\ApiResource;
use Illuminate\Database\Eloquent\Model;

#[ApiResource]
class Animal extends Model
{
    protected $fillable = ['id', 'name', 'age'];
}

This PR https://github.com/api-platform/docs/pull/2036 will solve the issue in the documentation

vinceAmstoutz avatar Oct 14 '24 11:10 vinceAmstoutz

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Dec 13 '24 17:12 stale[bot]