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

Cannot generate IRI errors when enabling rfc_7807_compliant_errors #6718

Open
darthf1 opened this issue Oct 13, 2024 · 5 comments
Open

Cannot generate IRI errors when enabling rfc_7807_compliant_errors #6718

darthf1 opened this issue Oct 13, 2024 · 5 comments

Comments

@darthf1
Copy link
Contributor

darthf1 commented Oct 13, 2024

API Platform version(s) affected: 3.4.3

Description
I'm trying to enable rfc_7807_compliant_errors as an upgrade path to v4. When I do this, in my project, not only the error output changes (obviously), but I also get:

ApiPlatform\Metadata\Exception\InvalidArgumentException: Unable to generate an IRI for the item of type  ....

How to reproduce
I have the following code:

<?php

namespace App;

#[ApiResource(
    shortName: 'Organisation',
    operations: [
        new Get(
            uriTemplate: '/organisations/{id}',
            security: "is_granted('" . OrganisationVoter::ATTRIBUTE_ORGANISATION_READ . "', object)",
            provider: ItemProvider::class,
        ),
        new Get(
            uriTemplate: '/users/{userId}/organisation',
            uriVariables: [
                'userId' => new Link(
                    fromClass: UserProjection::class,
                ),
            ],
            normalizationContext: [
                'item_uri_template' => '/organisations/{id}',
                'groups' => [self::NORMALIZATION_GROUP],
            ],
            provider: UserOrganisationProvider::class,
        ),
    ],
)]
class Organisation {}

I have two test cases:

  • fetching an Organisation for a given user, and the user has access to the Organisation, it returns the Organisation
  • fetching an Organisation for a given user, and the user does not have access to an Organisation, it returns HTTP 404.

The following happens:

  • With rfc_7807_compliant_errors to false, both test cases succeed.
  • With rfc_7807_compliant_errors to true, the second test case throws: ApiPlatform\Metadata\Exception\InvalidArgumentException: Unable to generate an IRI for the item of type "App\Organisation". When I then remove the line 'item_uri_template' => '/organisations/{id}', from the operation, the test succeeds again.

Additional Context
My (partial) config:

<?php

declare(strict_types=1);

use ApiPlatform\Metadata\Exception\InvalidArgumentException;
use ApiPlatform\Validator\Exception\ValidationException;
use Doctrine\ORM\OptimisticLockException;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Messenger\Exception\ValidationFailedException;
use Symfony\Component\Serializer\Exception\ExceptionInterface;

return static function (ContainerConfigurator $containerConfigurator): void {
    $containerConfigurator->extension('api_platform', [
        'defaults' => [
            'collectDenormalizationErrors' => true,
            'extra_properties' => [
                'standard_put' => true,
                'rfc_7807_compliant_errors' => true,
            ],
            'pagination_client_enabled' => true,
            'pagination_client_items_per_page' => true,
            'pagination_items_per_page' => 30,
            'pagination_maximum_items_per_page' => 100,
            'stateless' => true,
        ],
        'enable_link_security' => true,
        'exception_to_status' => [
            ExceptionInterface::class => Response::HTTP_BAD_REQUEST,
            InvalidArgumentException::class => Response::HTTP_BAD_REQUEST,
            OptimisticLockException::class => Response::HTTP_CONFLICT,
            ValidationException::class => Response::HTTP_UNPROCESSABLE_ENTITY,
            ValidationFailedException::class => Response::HTTP_UNPROCESSABLE_ENTITY,
        ],
        'keep_legacy_inflector' => false,
        'use_symfony_listeners' => true,
        'serializer' => [
            'hydra_prefix' => false,
        ],
    ]);
};

Full stacktrace:

ApiPlatform\Metadata\Exception\InvalidArgumentException: Unable to generate an IRI for the item of type "App\Organisation"
/home/www/app/vendor/api-platform/core/src/Symfony/Routing/IriConverter.php:194
/home/www/app/vendor/api-platform/core/src/Symfony/Routing/IriConverter.php:171
/home/www/app/vendor/api-platform/core/src/JsonLd/Serializer/ItemNormalizer.php:129
/home/www/app/vendor/api-platform/core/src/JsonLd/Serializer/ErrorNormalizer.php:31
/home/www/app/vendor/symfony/serializer/Serializer.php:150
/home/www/app/vendor/symfony/serializer/Serializer.php:129
/home/www/app/vendor/api-platform/core/src/State/Processor/SerializeProcessor.php:79
/home/www/app/vendor/api-platform/core/src/Symfony/EventListener/SerializeListener.php:102
/home/www/app/vendor/symfony/event-dispatcher/Debug/WrappedListener.php:115
/home/www/app/vendor/symfony/event-dispatcher/EventDispatcher.php:206
/home/www/app/vendor/symfony/event-dispatcher/EventDispatcher.php:56
/home/www/app/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:122
/home/www/app/vendor/symfony/http-kernel/HttpKernel.php:188
/home/www/app/vendor/symfony/http-kernel/HttpKernel.php:76
/home/www/app/vendor/symfony/http-kernel/EventListener/ErrorListener.php:97
/home/www/app/vendor/api-platform/core/src/Symfony/EventListener/ExceptionListener.php:50
/home/www/app/vendor/symfony/event-dispatcher/Debug/WrappedListener.php:115
/home/www/app/vendor/symfony/event-dispatcher/EventDispatcher.php:206
/home/www/app/vendor/symfony/event-dispatcher/EventDispatcher.php:56
/home/www/app/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:122
/home/www/app/vendor/symfony/http-kernel/HttpKernel.php:241
/home/www/app/vendor/symfony/http-kernel/HttpKernel.php:91
/home/www/app/vendor/symfony/http-kernel/Kernel.php:182
/home/www/app/vendor/symfony/http-kernel/HttpKernelBrowser.php:63
/home/www/app/vendor/symfony/framework-bundle/KernelBrowser.php:157
/home/www/app/vendor/symfony/browser-kit/AbstractBrowser.php:369
/home/www/app/vendor/api-platform/core/src/Symfony/Bundle/Test/Client.php:115
/home/www/app/tests/Functional/App/OrganisationTest.php:202

Caused by
ApiPlatform\Metadata\Exception\RuntimeException: Not able to retrieve identifiers.

/home/www/app/vendor/api-platform/core/src/Metadata/IdentifiersExtractor.php:139
/home/www/app/vendor/api-platform/core/src/Metadata/IdentifiersExtractor.php:90
/home/www/app/vendor/api-platform/core/src/Metadata/IdentifiersExtractor.php:60
/home/www/app/vendor/api-platform/core/src/Symfony/Routing/IriConverter.php:190
/home/www/app/vendor/api-platform/core/src/Symfony/Routing/IriConverter.php:171
/home/www/app/vendor/api-platform/core/src/JsonLd/Serializer/ItemNormalizer.php:129
/home/www/app/vendor/api-platform/core/src/JsonLd/Serializer/ErrorNormalizer.php:31
/home/www/app/vendor/symfony/serializer/Serializer.php:150
/home/www/app/vendor/symfony/serializer/Serializer.php:129
/home/www/app/vendor/api-platform/core/src/State/Processor/SerializeProcessor.php:79
/home/www/app/vendor/api-platform/core/src/Symfony/EventListener/SerializeListener.php:102
/home/www/app/vendor/symfony/event-dispatcher/Debug/WrappedListener.php:115
/home/www/app/vendor/symfony/event-dispatcher/EventDispatcher.php:206
/home/www/app/vendor/symfony/event-dispatcher/EventDispatcher.php:56
/home/www/app/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:122
/home/www/app/vendor/symfony/http-kernel/HttpKernel.php:188
/home/www/app/vendor/symfony/http-kernel/HttpKernel.php:76
/home/www/app/vendor/symfony/http-kernel/EventListener/ErrorListener.php:97
/home/www/app/vendor/api-platform/core/src/Symfony/EventListener/ExceptionListener.php:50
/home/www/app/vendor/symfony/event-dispatcher/Debug/WrappedListener.php:115
/home/www/app/vendor/symfony/event-dispatcher/EventDispatcher.php:206
/home/www/app/vendor/symfony/event-dispatcher/EventDispatcher.php:56
/home/www/app/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:122
/home/www/app/vendor/symfony/http-kernel/HttpKernel.php:241
/home/www/app/vendor/symfony/http-kernel/HttpKernel.php:91
/home/www/app/vendor/symfony/http-kernel/Kernel.php:182
/home/www/app/vendor/symfony/http-kernel/HttpKernelBrowser.php:63
/home/www/app/vendor/symfony/framework-bundle/KernelBrowser.php:157
/home/www/app/vendor/symfony/browser-kit/AbstractBrowser.php:369
/home/www/app/vendor/api-platform/core/src/Symfony/Bundle/Test/Client.php:115
/home/www/app/tests/Functional/App/OrganisationTest.php:202

Caused by
Symfony\Component\HttpKernel\Exception\NotFoundHttpException: Not Found

/home/www/app/vendor/api-platform/core/src/State/Provider/ReadProvider.php:94
/home/www/app/vendor/api-platform/core/src/Symfony/Validator/State/ParameterValidatorProvider.php:87
/home/www/app/vendor/api-platform/core/src/State/Provider/ParameterProvider.php:103
/home/www/app/vendor/api-platform/core/src/Symfony/Bundle/SwaggerUi/SwaggerUiProvider.php:50
/home/www/app/vendor/api-platform/core/src/Symfony/Security/State/AccessCheckerProvider.php:62
/home/www/app/vendor/api-platform/core/src/State/Provider/SecurityParameterProvider.php:39
/home/www/app/vendor/api-platform/core/src/Symfony/Security/State/LinkedReadProvider.php:42
/home/www/app/vendor/api-platform/core/src/Symfony/Security/State/LinkAccessCheckerProvider.php:40
/home/www/app/vendor/api-platform/core/src/Symfony/EventListener/ReadListener.php:95
/home/www/app/vendor/symfony/event-dispatcher/Debug/WrappedListener.php:115
/home/www/app/vendor/symfony/event-dispatcher/EventDispatcher.php:206
/home/www/app/vendor/symfony/event-dispatcher/EventDispatcher.php:56
/home/www/app/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:122
/home/www/app/vendor/symfony/http-kernel/HttpKernel.php:159
/home/www/app/vendor/symfony/http-kernel/HttpKernel.php:76
/home/www/app/vendor/symfony/http-kernel/Kernel.php:182
/home/www/app/vendor/symfony/http-kernel/HttpKernelBrowser.php:63
/home/www/app/vendor/symfony/framework-bundle/KernelBrowser.php:157
/home/www/app/vendor/symfony/browser-kit/AbstractBrowser.php:369
/home/www/app/vendor/api-platform/core/src/Symfony/Bundle/Test/Client.php:115
/home/www/app/tests/Functional/App/OrganisationTest.php:202
@soyuka
Copy link
Member

soyuka commented Oct 14, 2024

Hi @darthf1 API Platform was not able to gather identifiers from Organization, can you maybe api-resource:debug the first operation and check if it has uriVariables? I have no explanation for why the flag has this impact, what I usually do to debug exceptions is to dump directly inside the ErrorListener, my guess is that an exception is thrown no matter the rfc_7807_compliant_errors flag.

@darthf1
Copy link
Contributor Author

darthf1 commented Nov 14, 2024

What I found so far (I put some breakpoints in my app):

image

image
image

@soyuka
Copy link
Member

soyuka commented Nov 15, 2024

but you stil lget a 404? the error at:

image

Looks just fine to me

@darthf1
Copy link
Contributor Author

darthf1 commented Nov 15, 2024

Looks just fine to me

Yes absolutely! But that error is not handled gracefully anymore.

My tests does:

    public function testGetOwnOrganisationWhenNotMemberOfOrganisationThrowsHttpNotFound(): void
    {
        $referenceRepository = self::loadFixtures([
            UserTestFixture::class,
            OrganisationTestFixture::class,
        ]);
        $user3 = $referenceRepository->getReference(UserTestFixture::USER_3, User::class);

        $client = self::createAuthenticatedClient('[email protected]', 'user_3');
        $client->request('GET', \sprintf('/v1/users/%s/organisation', $user3->getId()));
        self::assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND);
    }
  • With rfc_7807_compliant_errors=false this tests succeeds
  • With rfc_7807_compliant_errors=true this test fails, and throws
ApiPlatform\Metadata\Exception\InvalidArgumentException: Unable to generate an IRI for the item of type "UserInterface\Organisation\Rest\OrganisationProjection"
  • With rfc_7807_compliant_errors=true and 'item_uri_template' => '/organisations/{id}', removed from the operations normalizationContext, this test succeeds as well.

@soyuka
Copy link
Member

soyuka commented Nov 18, 2024

May you provide a reproducer please?

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