Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error with Laravel and DTO #6717

Open
noweh opened this issue Oct 12, 2024 · 1 comment
Open

Error with Laravel and DTO #6717

noweh opened this issue Oct 12, 2024 · 1 comment

Comments

@noweh
Copy link

noweh commented Oct 12, 2024

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.

@vinceAmstoutz
Copy link
Contributor

vinceAmstoutz commented Oct 14, 2024

@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 api-platform/docs#2036 will solve the issue in the documentation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants