api-platform / core

The server component of API Platform: hypermedia and GraphQL APIs in minutes
https://api-platform.com
MIT License
2.43k stars 868 forks source link

Issues found on 2.7 #4613

Closed vincentchalamon closed 2 years ago

vincentchalamon commented 2 years ago

Write here as comment the errors you may found on api-platform/core:2.7.x-dev installed on your project. Please mention:

dannyvw commented 2 years ago

PHP 8.0 Symfony 5.4 API Platform 2.7.0-alpha.5 (metadata_backward_compatibility_layer: false)

Setting provider on operation is not working. Error "Provider not found on operation \"api/reset-password-request/{resetPasswordToken}_patch\""

<operation class="ApiPlatform\Metadata\Patch"
                       messenger="input"
                       input="App\Command\ResetPassword"
                       output="false"
                       status="202"
                       uriTemplate="/reset-password-request/{resetPasswordToken}"
                       provider="App\State\ResetPasswordProvider"
            >

Probably related to? https://github.com/api-platform/core/issues/4613#issuecomment-1112233470

soyuka commented 2 years ago

Is your provider registered as a Symfony service ? It's a basic service locator you can find that out using debug:container

lermontex commented 2 years ago

@soyuka, it seems the latest version ignores the route_prefix prefix settings

config/packages/api_platform.yaml

api_platform:
...
    metadata_backward_compatibility_layer: false
    openapi:
        backward_compatibility_layer: false
    defaults:
        route_prefix: '/api'

GET /users/{id} Retrieves a User resource. Instead of GET /api/users/{id} Retrieves a User resource.

Tested with d876e6638acad4b82887a4f93fd4eca361584d00

soyuka commented 2 years ago

Also: https://github.com/api-platform/core/pull/4755 (fix is in #4754)

dannyvw commented 2 years ago

@soyuka I have done some debugging for https://github.com/api-platform/core/issues/4613#issuecomment-1112233470 and it looks like the value is overwritten in https://github.com/api-platform/core/blob/main/src/Metadata/Property/Factory/LegacyPropertyMetadataFactory.php#L82

darthf1 commented 2 years ago

I'm trying to upgrade to 2.7 alpha 5 with the bc layer disabled. I used the CLI to convert the operations.

On calling the /docs endpoint, I get the exception below:

ErrorException:
Warning: Undefined array key "$ref"

  at vendor/api-platform/core/src/JsonSchema/TypeFactory.php:153
  at ApiPlatform\JsonSchema\TypeFactory->getClassType('UserInterface\\Bank\\Rest\\BankAccountProjection', 'jsonld', true, array('groups' => array('bank_statement_entry_detail_overview_normalize')), object(Schema))
     (vendor/api-platform/core/src/JsonSchema/TypeFactory.php:84)
  at ApiPlatform\JsonSchema\TypeFactory->makeBasicType(object(Type), 'jsonld', true, array('groups' => array('bank_statement_entry_detail_overview_normalize')), object(Schema))
     (vendor/api-platform/core/src/JsonSchema/TypeFactory.php:71)
  at ApiPlatform\JsonSchema\TypeFactory->getType(object(Type), 'jsonld', true, array('groups' => array('bank_statement_entry_detail_overview_normalize')), object(Schema))
     (vendor/api-platform/core/src/JsonSchema/SchemaFactory.php:269)
  at ApiPlatform\JsonSchema\SchemaFactory->buildPropertySchema(object(Schema), 'BankStatementEntryDetailOverviewProjection.jsonld-bank_statement_entry_detail_overview_normalize', 'bankAccount', object(ApiProperty), array('groups' => array('bank_statement_entry_detail_overview_normalize')), 'jsonld')
     (vendor/api-platform/core/src/JsonSchema/SchemaFactory.php:180)
  at ApiPlatform\JsonSchema\SchemaFactory->buildSchema('UserInterface\\Bank\\Rest\\BankStatementEntryDetailOverviewProjection', 'jsonld', 'output', null, '_api_/engagements/{id}/bank_statement_entry_detail_overviews.{_format}_get_collection', object(Schema), array('groups' => array('bank_statement_entry_detail_overview_normalize')), true)
     (vendor/api-platform/core/src/Hydra/JsonSchema/SchemaFactory.php:75)
  at ApiPlatform\Hydra\JsonSchema\SchemaFactory->buildSchema('UserInterface\\Bank\\Rest\\BankStatementEntryDetailOverviewProjection', 'jsonld', 'output', null, '_api_/engagements/{id}/bank_statement_entry_detail_overviews.{_format}_get_collection', object(Schema), null, true)
     (vendor/api-platform/core/src/OpenApi/Factory/OpenApiFactory.php:177)
  at ApiPlatform\OpenApi\Factory\OpenApiFactory->collectPaths(object(ApiResource), object(ResourceMetadataCollection), object(Paths), object(ArrayObject))
     (vendor/api-platform/core/src/OpenApi/Factory/OpenApiFactory.php:104)
  at ApiPlatform\OpenApi\Factory\OpenApiFactory->__invoke(array('base_url' => '/'))
     (vendor/api-platform/core/src/Symfony/Bundle/SwaggerUi/SwaggerUiAction.php:66)
  at ApiPlatform\Symfony\Bundle\SwaggerUi\SwaggerUiAction->__invoke(object(Request))
     (vendor/api-platform/core/src/Core/Bridge/Symfony/Bundle/Action/SwaggerUiAction.php:136)
  at ApiPlatform\Core\Bridge\Symfony\Bundle\Action\SwaggerUiAction->__invoke(object(Request))
     (vendor/symfony/http-kernel/HttpKernel.php:152)
  at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), 1)
     (vendor/symfony/http-kernel/HttpKernel.php:74)
  at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), 1, true)
     (vendor/symfony/http-kernel/Kernel.php:202)
  at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
     (vendor/symfony/runtime/Runner/Symfony/HttpKernelRunner.php:35)
  at Symfony\Component\Runtime\Runner\Symfony\HttpKernelRunner->run()
     (vendor/autoload_runtime.php:29)
  at require_once('/home/www/app/vendor/autoload_runtime.php')
     (public/index.php:14)

Is it true that classes in namespace ApiPlatform\Core are part of the "old" structure? So the class ApiPlatform\Core\Bridge\Symfony\Bundle\Action\SwaggerUiAction in the stacktrace means the old bundle is being used?

I have in my bundles.php:

<?php

return [
    ApiPlatform\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
];

api_platform.yaml:

api_platform:
  metadata_backward_compatibility_layer: false
  title: "API Platform"
  version: "0.0.0-alpha"
  defaults:
    pagination_client_enabled: true
    pagination_client_items_per_page: true
    pagination_items_per_page: 30
    pagination_maximum_items_per_page: 100
  collection:
    pagination:
      enabled_parameter_name: pagination
  elasticsearch:
    enabled: true
    hosts: [ '%env(ELASTICSEARCH_URL)%' ]
  formats:
    jsonld: [ 'application/ld+json' ]
    json: [ 'application/json' ]
    xlsx: [ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ]
    zip: [ 'application/zip' ]
  http_cache:
    invalidation:
      enabled: false
  mapping:
    paths:
      - '%kernel.project_dir%/src/UserInterface'
  patch_formats:
    json: [ 'application/merge-patch+json' ]
  swagger:
    versions: [ 3 ]
    api_keys:
      apiKey:
        name: Authorization
        type: header
  exception_to_status:
    # The 4 following handlers are registered by default, keep those lines to prevent unexpected side effects
    ApiPlatform\Exception\InvalidArgumentException: !php/const Symfony\Component\HttpFoundation\Response::HTTP_BAD_REQUEST
    ApiPlatform\Exception\FilterValidationException: !php/const Symfony\Component\HttpFoundation\Response::HTTP_BAD_REQUEST
    Doctrine\ORM\OptimisticLockException: !php/const Symfony\Component\HttpFoundation\Response::HTTP_CONFLICT
    Symfony\Component\Serializer\Exception\ExceptionInterface: !php/const Symfony\Component\HttpFoundation\Response::HTTP_BAD_REQUEST
    # Validation exception
    ApiPlatform\Symfony\Validator\Exception\ValidationException: !php/const Symfony\Component\HttpFoundation\Response::HTTP_UNPROCESSABLE_ENTITY
    # Custom mapping
    DomainException: !php/const Symfony\Component\HttpFoundation\Response::HTTP_BAD_REQUEST
    Symfony\Component\Messenger\Exception\HandlerFailedException: !php/const Symfony\Component\HttpFoundation\Response::HTTP_BAD_REQUEST

Edit:

I have the following in my routes.yaml:

api_doc:
  path: /v1/docs
  controller: api_platform.swagger.action.ui

If I change it to:

api_doc:
  path: /v1/docs
  controller: api_platform.action.documentation

I get:

Symfony\Component\Serializer\Exception\NotEncodableValueException:
Serialization for the format "html" is not supported.

  at vendor/symfony/serializer/Serializer.php:130
  at Symfony\Component\Serializer\Serializer->serialize(object(Documentation), 'html', array('base_url' => '', 'spec_version' => 3))
     (vendor/api-platform/core/src/Symfony/EventListener/SerializeListener.php:145)
  at ApiPlatform\Symfony\EventListener\SerializeListener->serializeRawData(object(ViewEvent), object(Request), object(Documentation))
     (vendor/api-platform/core/src/Symfony/EventListener/SerializeListener.php:97)
  at ApiPlatform\Symfony\EventListener\SerializeListener->onKernelView(object(ViewEvent), 'kernel.view', object(TraceableEventDispatcher))
     (vendor/symfony/event-dispatcher/Debug/WrappedListener.php:111)
  at Symfony\Component\EventDispatcher\Debug\WrappedListener->__invoke(object(ViewEvent), 'kernel.view', object(TraceableEventDispatcher))
     (vendor/symfony/event-dispatcher/EventDispatcher.php:230)
  at Symfony\Component\EventDispatcher\EventDispatcher->callListeners(array(object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener)), 'kernel.view', object(ViewEvent))
     (vendor/symfony/event-dispatcher/EventDispatcher.php:59)
  at Symfony\Component\EventDispatcher\EventDispatcher->dispatch(object(ViewEvent), 'kernel.view')
     (vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:152)
  at Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher->dispatch(object(ViewEvent), 'kernel.view')
     (vendor/symfony/http-kernel/HttpKernel.php:159)
  at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), 1)
     (vendor/symfony/http-kernel/HttpKernel.php:74)
  at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), 1, true)
     (vendor/symfony/http-kernel/Kernel.php:202)
  at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
     (vendor/symfony/runtime/Runner/Symfony/HttpKernelRunner.php:35)
  at Symfony\Component\Runtime\Runner\Symfony\HttpKernelRunner->run()
     (vendor/autoload_runtime.php:29)
  at require_once('/home/www/app/vendor/autoload_runtime.php')
     (public/index.php:14)            

If I change it to:

api_doc:
  path: /v1/docs
  controller: api_platform.swagger_ui.action

I get:

ErrorException:
Warning: Undefined array key "$ref"

  at vendor/api-platform/core/src/JsonSchema/TypeFactory.php:153
  at ApiPlatform\JsonSchema\TypeFactory->getClassType('UserInterface\\Bank\\Rest\\BankAccountProjection', 'jsonld', true, array('groups' => array('bank_statement_entry_detail_overview_normalize')), object(Schema))
     (vendor/api-platform/core/src/JsonSchema/TypeFactory.php:84)
  at ApiPlatform\JsonSchema\TypeFactory->makeBasicType(object(Type), 'jsonld', true, array('groups' => array('bank_statement_entry_detail_overview_normalize')), object(Schema))
     (vendor/api-platform/core/src/JsonSchema/TypeFactory.php:71)
  at ApiPlatform\JsonSchema\TypeFactory->getType(object(Type), 'jsonld', true, array('groups' => array('bank_statement_entry_detail_overview_normalize')), object(Schema))
     (vendor/api-platform/core/src/JsonSchema/SchemaFactory.php:269)
  at ApiPlatform\JsonSchema\SchemaFactory->buildPropertySchema(object(Schema), 'BankStatementEntryDetailOverviewProjection.jsonld-bank_statement_entry_detail_overview_normalize', 'bankAccount', object(ApiProperty), array('groups' => array('bank_statement_entry_detail_overview_normalize')), 'jsonld')
     (vendor/api-platform/core/src/JsonSchema/SchemaFactory.php:180)
  at ApiPlatform\JsonSchema\SchemaFactory->buildSchema('UserInterface\\Bank\\Rest\\BankStatementEntryDetailOverviewProjection', 'jsonld', 'output', null, '_api_/engagements/{id}/bank_statement_entry_detail_overviews.{_format}_get_collection', object(Schema), array('groups' => array('bank_statement_entry_detail_overview_normalize')), true)
     (vendor/api-platform/core/src/Hydra/JsonSchema/SchemaFactory.php:75)
  at ApiPlatform\Hydra\JsonSchema\SchemaFactory->buildSchema('UserInterface\\Bank\\Rest\\BankStatementEntryDetailOverviewProjection', 'jsonld', 'output', null, '_api_/engagements/{id}/bank_statement_entry_detail_overviews.{_format}_get_collection', object(Schema), null, true)
     (vendor/api-platform/core/src/OpenApi/Factory/OpenApiFactory.php:177)
  at ApiPlatform\OpenApi\Factory\OpenApiFactory->collectPaths(object(ApiResource), object(ResourceMetadataCollection), object(Paths), object(ArrayObject))
     (vendor/api-platform/core/src/OpenApi/Factory/OpenApiFactory.php:104)
  at ApiPlatform\OpenApi\Factory\OpenApiFactory->__invoke(array('base_url' => '/'))
     (vendor/api-platform/core/src/Symfony/Bundle/SwaggerUi/SwaggerUiAction.php:66)
  at ApiPlatform\Symfony\Bundle\SwaggerUi\SwaggerUiAction->__invoke(object(Request))
     (vendor/symfony/http-kernel/HttpKernel.php:154)
  at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), 1)
     (vendor/symfony/http-kernel/HttpKernel.php:74)
  at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), 1, true)
     (vendor/symfony/http-kernel/Kernel.php:202)
  at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
     (vendor/symfony/runtime/Runner/Symfony/HttpKernelRunner.php:35)
  at Symfony\Component\Runtime\Runner\Symfony\HttpKernelRunner->run()
     (vendor/autoload_runtime.php:29)
  at require_once('/home/www/app/vendor/autoload_runtime.php')
     (public/index.php:14)           

image

It looks like there's an error with the subresource operation which is generated from the old attribute:

<?php

#[ApiResource(
    uriTemplate: '/engagements/{id}/bank_statement_entry_detail_overviews.{_format}',
    uriVariables: ['id' => new Link(fromClass: EngagementProjection::class, identifiers: ['id'])],
    normalizationContext: ['groups' => [self::NORMALIZATION_GROUP]],
    operations: [new GetCollection()],
    paginationEnabled: false,
)]

If I remove this, I still get the error, but on the next class which has a similar attribute.

If my resources are not also doctrine entities, how should the subresource be declared? In the docs it looks like the examples are for doctrine entities only.

soyuka commented 2 years ago

If you have only this operation you could even do something like this:

#[GetCollection(
    uriTemplate: '/engagements/{id}/bank_statement_entry_detail_overviews.{_format}',
    uriVariables: ['id' => new Link(fromClass: EngagementProjection::class, identifiers: ['id'])],
    normalizationContext: ['groups' => [self::NORMALIZATION_GROUP]],
    paginationEnabled: false,
)]

The links system is plugged with Doctrine but you should be able to make it work with your own provider. Note that in beta.5 providers and processors are also declared on the resource (check the debug:api command if you want to see what the defaults are).

The error above is tighten to the SchemaFactory, we forgot the bc layer on it and I just fixed it, will release asap hoping it fixes your issue.

soyuka commented 2 years ago

@dannyvw https://github.com/api-platform/core/pull/4767 should fix it

darthf1 commented 2 years ago

The error above is tighten to the SchemaFactory, we forgot the bc layer on it and I just fixed it, will release asap hoping it fixes your issue.

Great thanks! I'll wait for the new release :)

But since I have metadata_backward_compatibility_layer: false, is the BC layer still relevant?

Edit: @soyuka I just tested it with alpha 7 and the issue is still there.

soyuka commented 2 years ago

it may be that the schema was not properly generated with new metadata but indeed it's weird, I need to try and reproduce this issue.

FabienPapet commented 2 years ago

I don't know if it a bug or just a misconfiguration. but if I create a /duplicate custom operation on a resource, the @id returned in the response is the url of the route /duplicate

I think the error comes from vendor/api-platform/core/src/Symfony/Routing/IriConverter.php:175 The code comes from this test.

$client = static::createClient();
$response = $client->request('GET', '/api/invoices/9de5c55a-fe43-4acd-8f5a-5175bf51f6bd/duplicate', [
       'auth_basic' => ['admin', 'admin'],
])->toArray();
$id = $response['@id']; // /api/invoices/cb10e2d4-9347-4291-9e37-11c5e01b975d/duplicate
image image
soyuka commented 2 years ago

ExtraProperties is not inherited by the operations.

pavleocom commented 2 years ago

namespace App\Entity;

use ApiPlatform\Metadata\ApiResource; use App\Repository\TestRepository; use Doctrine\ORM\Mapping as ORM;

[ORM\Entity(repositoryClass: TestRepository::class)]

[ApiResource]

class Test {

[ORM\Id]

#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private $id;

public function getId(): ?int
{
    return $this->id;
}

}


- Full repo of the project: https://github.com/pavleocom/apip-test

What's missing?
pavleocom commented 2 years ago
  • CRUD operations aren't getting registered
  • PHP 8.0.19, Symfony 6.0, Api-Platform v2.7.0-alpha.7
  • Output from bin/console debug:router:
  Name                 Method   Scheme   Host   Path                                 
 -------------------- -------- -------- ------ ------------------------------------- 
  api_entrypoint       ANY      ANY      ANY    /api/{index}.{_format}               
  api_doc              ANY      ANY      ANY    /api/docs.{_format}                  
  api_jsonld_context   ANY      ANY      ANY    /api/contexts/{shortName}.{_format}  
  _preview_error       ANY      ANY      ANY    /_error/{code}.{_format}             
 -------------------- -------- -------- ------ ------------------------------------- 
  • Entity /src/Entity/Test.php:
<?php

namespace App\Entity;

use ApiPlatform\Metadata\ApiResource;
use App\Repository\TestRepository;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: TestRepository::class)]
#[ApiResource]
class Test
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private $id;

    public function getId(): ?int
    {
        return $this->id;
    }
}

What's missing?

Resolved by adding this:

#/src/config/api_platform.yaml
api_platform:
    metadata_backward_compatibility_layer: false

When you are upgrading using the api:upgrade-resource it does tell you to set metadata_backward_compatibility_layer to false but I installed APIP 2.7 as a new project from scratch and documentation for APIP 2.7 operations does not mention anything about this.

soyuka commented 2 years ago

CacheHeaders issues

soyuka commented 2 years ago

@darthf1 maybe add the html format in your configuration, I need to find time to dig into this a bit more

darthf1 commented 2 years ago

@soyuka you mean like this?

api_platform:
  formats:
    jsonld: [ 'application/ld+json' ]
    json: [ 'application/json' ]
    xlsx: [ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ]
    zip: [ 'application/zip' ]
    html: [ 'text/html' ] <--- added

Tried with beta1, stacktrace is the same (with different line numbers):

ErrorException:
Warning: Undefined array key "$ref"

  at vendor/api-platform/core/src/JsonSchema/TypeFactory.php:159
  at ApiPlatform\JsonSchema\TypeFactory->getClassType('UserInterface\\Bank\\Rest\\BankAccountProjection', 'jsonld', true, array('groups' => array('bank_statement_entry_detail_overview_normalize')), object(Schema))
     (vendor/api-platform/core/src/JsonSchema/TypeFactory.php:90)
  at ApiPlatform\JsonSchema\TypeFactory->makeBasicType(object(Type), 'jsonld', true, array('groups' => array('bank_statement_entry_detail_overview_normalize')), object(Schema))
     (vendor/api-platform/core/src/JsonSchema/TypeFactory.php:77)
  at ApiPlatform\JsonSchema\TypeFactory->getType(object(Type), 'jsonld', true, array('groups' => array('bank_statement_entry_detail_overview_normalize')), object(Schema))
     (vendor/api-platform/core/src/JsonSchema/SchemaFactory.php:218)
  at ApiPlatform\JsonSchema\SchemaFactory->buildPropertySchema(object(Schema), 'BankStatementEntryDetailOverviewProjection.jsonld-bank_statement_entry_detail_overview_normalize', 'bankAccount', object(ApiProperty), array('groups' => array('bank_statement_entry_detail_overview_normalize')), 'jsonld')
     (vendor/api-platform/core/src/JsonSchema/SchemaFactory.php:142)
  at ApiPlatform\JsonSchema\SchemaFactory->buildSchema('UserInterface\\Bank\\Rest\\BankStatementEntryDetailOverviewProjection', 'jsonld', 'output', object(GetCollection), object(Schema), array('groups' => array('bank_statement_entry_detail_overview_normalize')), true)
     (vendor/api-platform/core/src/Hydra/JsonSchema/SchemaFactory.php:76)
  at ApiPlatform\Hydra\JsonSchema\SchemaFactory->buildSchema('UserInterface\\Bank\\Rest\\BankStatementEntryDetailOverviewProjection', 'jsonld', 'output', object(GetCollection), object(Schema), null, true)
     (vendor/api-platform/core/src/OpenApi/Factory/OpenApiFactory.php:177)
  at ApiPlatform\OpenApi\Factory\OpenApiFactory->collectPaths(object(ApiResource), object(ResourceMetadataCollection), object(Paths), object(ArrayObject))
     (vendor/api-platform/core/src/OpenApi/Factory/OpenApiFactory.php:104)
  at ApiPlatform\OpenApi\Factory\OpenApiFactory->__invoke(array('base_url' => '/'))
     (vendor/api-platform/core/src/Symfony/Bundle/SwaggerUi/SwaggerUiAction.php:66)
  at ApiPlatform\Symfony\Bundle\SwaggerUi\SwaggerUiAction->__invoke(object(Request))
     (vendor/symfony/http-kernel/HttpKernel.php:152)
  at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), 1)
     (vendor/symfony/http-kernel/HttpKernel.php:74)
  at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), 1, true)
     (vendor/symfony/http-kernel/Kernel.php:202)
  at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
     (vendor/symfony/runtime/Runner/Symfony/HttpKernelRunner.php:35)
  at Symfony\Component\Runtime\Runner\Symfony\HttpKernelRunner->run()
     (vendor/autoload_runtime.php:29)
  at require_once('/home/www/app/vendor/autoload_runtime.php')
     (public/index.php:14)     
dannyvw commented 2 years ago

API Platform: v2.7.0-beta.1

Extending AbstractFilter triggers the following error on requestStack variable

A binding is configured for an argument named "$requestStack" for service "App\Doctrine\Filter\NameFilter", but no corresponding argument has been found. It may be unused and should be removed, or it may have a typo.

This is triggered by https://github.com/api-platform/core/blob/2.7/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php#L667 and should only be applied on the old AbstractFilter class.

Example class

<?php

use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter;

final class NameFilter extends AbstractFilter
robregonm commented 2 years ago

API Platform: v2.7.0-beta.1

When you run ./bin/console api:upgrade-resource You get an exception:

 In UpgradeApiResourceCommand.php line 196:

   Attempted to load class "Differ" from namespace "SebastianBergmann\Diff".  
   Did you forget a "use" statement for "PhpParser\Internal\Differ"?          

Such class/package is not set in composer.json. You can bypass the error executing: ./bin/console api:upgrade-resource --silent --force

bendavies commented 2 years ago

regression in ApiTestCase::assertMatchesResourceItemJsonSchema

given a resource with a normalization context on 2.6:

#[ApiResource(
    collectionOperations: ['get'],
    itemOperations: ['get'],
    normalizationContext: ['groups' => ['policy-notice:read']],
)]
class PolicyNotice {}

converted to 2.7 Metadata:

#[ApiResource(
    operations: [
        new Get(),
        new GetCollection(),
    ],
    normalizationContext: ['groups' => ['policy-notice:read']],
)]
class PolicyNotice {}

this no longer works on 2.7

$this->assertMatchesResourceItemJsonSchema(PolicyNotice::class);

because 2.7 tries to "guess" the operation and can't find one, so creates a new one with the wrong (empty) serialization context.

https://github.com/api-platform/core/blob/4c16efe1f39c8aadd20e8e08b0b57a4d33034cd8/src/JsonSchema/SchemaFactory.php#L284

in 2.7 I can fix this by manually providing the operation name:

$this->assertMatchesResourceItemJsonSchema(PolicyNotice::class, '_api_/policy-notices/{id}.{_format}_get');
dannyvw commented 2 years ago

API Platform: v2.7.0-beta.1 (metadata_backward_compatibility_layer: false)

When configuring skip_null_values it is set as string instead of boolean in https://github.com/api-platform/core/blob/main/src/Serializer/SerializerContextBuilder.php#L65

Operation xml configuration

<operation class="ApiPlatform\Metadata\Put">
    <normalizationContext>
        <values>
            <value name="skip_null_values">false</value>
        </values>
    </normalizationContext>
</operation>
welcoMattic commented 2 years ago

API Platform: v2.7.1-beta.1

ReflectionException: Class "(string|null)" does not exist

/app/vendor/api-platform/core/src/JsonSchema/SchemaFactory.php:287
/app/vendor/api-platform/core/src/JsonSchema/SchemaFactory.php:101
/app/vendor/api-platform/core/src/Hydra/JsonSchema/SchemaFactory.php:75

The line that triggers this error is:

$this->assertMatchesResourceItemJsonSchema(Program::class, 'get');

There are several public ?string $foo similar properties in Program class.

cc @vincentchalamon

soyuka commented 2 years ago

@bendavies added a fix for this at https://github.com/api-platform/core/pull/4796 released as beta.2

@welcoMattic note that operation names have changed, not sure I understand the issue. (they change only when using the legacy flag to false)

pavel-m10c commented 2 years ago

API Platform 2.7 Beta-1 Symfony 6.0 PHP 8.1

Issue:

Denormalizing IRIs into objects doesn't seem to work when using DTO input class.

It does work if input class is not used.

Stack trace:

{
    "@context": "/contexts/Error",
    "@type": "hydra:Error",
    "hydra:title": "An error occurred",
    "hydra:description": "Failed to denormalize attribute \"order\" value for class \"App\\Dto\\Order\\OrderItemDto\": Expected argument of type \"?App\\Entity\\Order\", \"string\" given at property path \"order\".",
    "trace": [
        {
            "namespace": "",
            "short_class": "",
            "class": "",
            "type": "",
            "function": "",
            "file": "***/vendor/symfony/serializer/Exception/NotNormalizableValueException.php",
            "line": 31,
            "args": []
        },
        {
            "namespace": "Symfony\\Component\\Serializer\\Exception",
            "short_class": "NotNormalizableValueException",
            "class": "Symfony\\Component\\Serializer\\Exception\\NotNormalizableValueException",
            "type": "::",
            "function": "createForUnexpectedDataType",
            "file": "***/vendor/symfony/serializer/Normalizer/AbstractObjectNormalizer.php",
            "line": 403,
            "args": []
        },
        {
            "namespace": "Symfony\\Component\\Serializer\\Normalizer",
            "short_class": "AbstractObjectNormalizer",
            "class": "Symfony\\Component\\Serializer\\Normalizer\\AbstractObjectNormalizer",
            "type": "->",
            "function": "denormalize",
            "file": "***/vendor/api-platform/core/src/Serializer/AbstractItemNormalizer.php",
            "line": 314,
            "args": []
        },
        {
            "namespace": "ApiPlatform\\Serializer",
            "short_class": "AbstractItemNormalizer",
            "class": "ApiPlatform\\Serializer\\AbstractItemNormalizer",
            "type": "->",
            "function": "denormalize",
            "file": "***/vendor/api-platform/core/src/Serializer/ItemNormalizer.php",
            "line": 77,
            "args": []
        },
        {
            "namespace": "ApiPlatform\\Serializer",
            "short_class": "ItemNormalizer",
            "class": "ApiPlatform\\Serializer\\ItemNormalizer",
            "type": "->",
            "function": "denormalize",
            "file": "***/src/Serializer/DecoratingNormalizer.php",
            "line": 84,
            "args": []
        },
        {
            "namespace": "App\\Serializer",
            "short_class": "DecoratingNormalizer",
            "class": "App\\Serializer\\DecoratingNormalizer",
            "type": "->",
            "function": "denormalize",
            "file": "***/vendor/symfony/serializer/Serializer.php",
            "line": 238,
            "args": []
        },
        {
            "namespace": "Symfony\\Component\\Serializer",
            "short_class": "Serializer",
            "class": "Symfony\\Component\\Serializer\\Serializer",
            "type": "->",
            "function": "denormalize",
            "file": "***/vendor/symfony/serializer/Serializer.php",
            "line": 151,
            "args": []
        },
        {
            "namespace": "Symfony\\Component\\Serializer",
            "short_class": "Serializer",
            "class": "Symfony\\Component\\Serializer\\Serializer",
            "type": "->",
            "function": "deserialize",
            "file": "***/vendor/api-platform/core/src/Symfony/EventListener/DeserializeListener.php",
            "line": 137,
            "args": []
        },
        {
            "namespace": "ApiPlatform\\Symfony\\EventListener",
            "short_class": "DeserializeListener",
            "class": "ApiPlatform\\Symfony\\EventListener\\DeserializeListener",
            "type": "->",
            "function": "onKernelRequest",
            "file": "***/vendor/symfony/event-dispatcher/Debug/WrappedListener.php",
            "line": 111,
            "args": []
        },
        {
            "namespace": "Symfony\\Component\\EventDispatcher\\Debug",
            "short_class": "WrappedListener",
            "class": "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener",
            "type": "->",
            "function": "__invoke",
            "file": "***/vendor/symfony/event-dispatcher/EventDispatcher.php",
            "line": 230,
            "args": []
        },
        {
            "namespace": "Symfony\\Component\\EventDispatcher",
            "short_class": "EventDispatcher",
            "class": "Symfony\\Component\\EventDispatcher\\EventDispatcher",
            "type": "->",
            "function": "callListeners",
            "file": "***/vendor/symfony/event-dispatcher/EventDispatcher.php",
            "line": 59,
            "args": []
        },
        {
            "namespace": "Symfony\\Component\\EventDispatcher",
            "short_class": "EventDispatcher",
            "class": "Symfony\\Component\\EventDispatcher\\EventDispatcher",
            "type": "->",
            "function": "dispatch",
            "file": "***/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php",
            "line": 152,
            "args": []
        },
        {
            "namespace": "Symfony\\Component\\EventDispatcher\\Debug",
            "short_class": "TraceableEventDispatcher",
            "class": "Symfony\\Component\\EventDispatcher\\Debug\\TraceableEventDispatcher",
            "type": "->",
            "function": "dispatch",
            "file": "***/vendor/symfony/http-kernel/HttpKernel.php",
            "line": 128,
            "args": []
        },
        {
            "namespace": "Symfony\\Component\\HttpKernel",
            "short_class": "HttpKernel",
            "class": "Symfony\\Component\\HttpKernel\\HttpKernel",
            "type": "->",
            "function": "handleRaw",
            "file": "***/vendor/symfony/http-kernel/HttpKernel.php",
            "line": 74,
            "args": []
        },
        {
            "namespace": "Symfony\\Component\\HttpKernel",
            "short_class": "HttpKernel",
            "class": "Symfony\\Component\\HttpKernel\\HttpKernel",
            "type": "->",
            "function": "handle",
            "file": "***/vendor/symfony/http-kernel/Kernel.php",
            "line": 202,
            "args": []
        },
        {
            "namespace": "Symfony\\Component\\HttpKernel",
            "short_class": "Kernel",
            "class": "Symfony\\Component\\HttpKernel\\Kernel",
            "type": "->",
            "function": "handle",
            "file": "***/vendor/symfony/runtime/Runner/Symfony/HttpKernelRunner.php",
            "line": 35,
            "args": []
        },
        {
            "namespace": "Symfony\\Component\\Runtime\\Runner\\Symfony",
            "short_class": "HttpKernelRunner",
            "class": "Symfony\\Component\\Runtime\\Runner\\Symfony\\HttpKernelRunner",
            "type": "->",
            "function": "run",
            "file": "***/vendor/autoload_runtime.php",
            "line": 29,
            "args": []
        },
        {
            "namespace": "",
            "short_class": "",
            "class": "",
            "type": "",
            "function": "require_once",
            "file": "***/public/index.php",
            "line": 5,
            "args": [
                [
                    "string",
                    "***/vendor/autoload_runtime.php"
                ]
            ]
        }
    ]
}

Entity: OrderItem (ApiResource attribute only)

#[ApiResource(
    operations: [
        new GetNotFound(),
        new Post(
            input: OrderItemDto::class,
            processor: OrderAddItemProcessor::class,
            denormalizationContext: [
                'groups' => [
                    'Order:W$AddOrderItem',
                ],
            ],
        ),
    ],
)]

DTO: OrderItemDto

<?php

declare(strict_types=1);

namespace App\Dto\Order;

use App\Entity\Order;
use Symfony\Component\Serializer\Annotation as Serializer;

class OrderItemDto
{

    #[Serializer\Groups([
        'Order:W$AddOrderItem',
    ])]
    public ?Order $order = null;

}

HTTP Request:

POST /order-items HTTP/1.1
Host: 127.0.0.1:8000
Authorization: Bearer ***
Content-Type: application/json
Content-Length: 49

{
    "order": "/orders/gbZ5Llr8cU_a82CHDJwEEM"
}
bendavies commented 2 years ago

@soyuka thankyou!

soyuka commented 2 years ago

use Content-Type: application/ld+json maybe ?

pavel-m10c commented 2 years ago

use Content-Type: application/ld+json maybe ?

Note when input class is not used (i.e. when entity class is used) IRIs do get converted into objects with the same http request. Nevertheless, I've tried changing the request header and it didn't make any difference.

@soyuka

soyuka commented 2 years ago

I don't understand we have a test case covering this (https://github.com/api-platform/core/blob/main/features/jsonld/input_output.feature#L199) and I checked it works on 2.7. I need to try this without any Data Transformer though but I'm working hard on the 3.0. I'll come back to this, if you have the time to add a Behat test covering your issue in a PR against 2.7 it'd save me some time! Thanks!

pavel-m10c commented 2 years ago

It seems it's not just IRIs but rather denormalizer not being able to determine what type the property is supposed to be and thus just using the original value which is string (or number). For example, when I have a property of type DateTime in my input class, and the request contains a valid Y-m-d date string for that property, it fails with the same exception.

With all that said, I wasn't able to create a failing test covering this issue. I must be doing something wrong in my project? I've created a sample project which suffers from the same problem: https://github.com/pavleocom/apip-test

I'd be grateful if you or someone else could take a look and advise on what I might be doing wrong.

jonag commented 2 years ago

I have a very similar issue with a new project I use to experiment with the new metadata system of API Platform 2.7.

I have an API Resource with a Post operation mapped to an Input class (which is not an API Resource). One of the property of this input class is another class (also not an API Resource).

When I try to call the the operation, I get the following exception :

App\Dto\NouveauClient::__construct(): Argument #3 ($adresse) must be of type App\Dto\NouvelleAdresse, array given

With Xdebug I found that the method denormalize of the ApiPlatform\JsonLd\Serializer\ItemNormalizer call the method denormalize of ApiPlatform\Serializer\AbstractItemNormalizer and then the method denormalize of Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer (all of which are just parent calls).

The denormalize of Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer call getTypes but at this step $this->propertyTypeExtractor evaluates to null so no type is returned and the raw value from my json payload (an array) is passed to the constructor of my input, hence the exception.

If I inject the service property_info in ApiPlatform\JsonLd\Serializer\ItemNormalizer and pass it all the way to Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer then everything works just fine. However I'm not sure this is really the right fix because I can't reproduce the issue using the test suite (I've tried to modify this feature to mimic my case but it works just fine).

During my tests I'm using api-platform/core@v2.7.0-beta.1 and symfony/serializer@v6.1.1.

soyuka commented 2 years ago

Interesting findings @jonag thanks, I'll make sure that the property_info is defined and let you know when its patched. I'm working on improvements in 3.0 that I'll backport to 2.7 once its stable enough (they should fix your issues above).

Zul3s commented 2 years ago

Hi,

Symfony 5.4 PHP 7.4 Easycorp/easyadmin-bundle : 3.5.21

API Platform version(s) affected: ^v2.7.0-beta.1

Description
When I try to access an EasyAdmin page, I get a 500 error:

`Serialization for the format "html" is not supported.

Symfony\Component\Serializer\Exception\NotEncodableValueException: Serialization for the format "html" is not supported.

at vendor/symfony/serializer/Serializer.php:130 at Symfony\Component\Serializer\Serializer->serialize(object(KeyValueStore), 'html', array()) (vendor/api-platform/core/src/Symfony/EventListener/SerializeListener.php:145) at ApiPlatform\Symfony\EventListener\SerializeListener->serializeRawData(object(ViewEvent), object(Request), object(KeyValueStore)) (vendor/api-platform/core/src/Symfony/EventListener/SerializeListener.php:97) at ApiPlatform\Symfony\EventListener\SerializeListener->onKernelView(object(ViewEvent), 'kernel.view', object(TraceableEventDispatcher)) (vendor/symfony/event-dispatcher/Debug/WrappedListener.php:117) at Symfony\Component\EventDispatcher\Debug\WrappedListener->__invoke(object(ViewEvent), 'kernel.view', object(TraceableEventDispatcher)) (vendor/symfony/event-dispatcher/EventDispatcher.php:230) at Symfony\Component\EventDispatcher\EventDispatcher->callListeners(array(object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener)), 'kernel.view', object(ViewEvent)) (vendor/symfony/event-dispatcher/EventDispatcher.php:59) at Symfony\Component\EventDispatcher\EventDispatcher->dispatch(object(ViewEvent), 'kernel.view') (vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:154) at Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher->dispatch(object(ViewEvent), 'kernel.view') (vendor/symfony/http-kernel/HttpKernel.php:157) at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), 1) (vendor/symfony/http-kernel/HttpKernel.php:74) at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), 1, true) (vendor/symfony/http-kernel/Kernel.php:202) at Symfony\Component\HttpKernel\Kernel->handle(object(Request)) (public/index.php:55) `

How to reproduce
When you have projet with Symfony 5.4, EasyAdmin 3.5.21 and Api Platform v2.7.0-beta.1, you have to try access to an EasyAdmin CRUD page.

Possible Solution
I believe that the problem comes from the fact that ApiPlatform as well as EasyAdmin are connected to kernel.view event and that it is indeed the API Platform listeners which are executed first. I don't know if the best solution is to manage a condition in the API Platform listeners to exclude the EasyAdmin case? Or only include API Platform cases? Or even change the priority of the listeners? Additional Context
/

EDIT Fix : https://github.com/api-platform/core/pull/4828/commits Thank @vincentchalamon

soyuka commented 2 years ago

@pavel-m10c @jonag I tagged a new beta, please let me know if it fixes the issue.

To everyone else: 3.0 is coming out tomorrow !

jonag commented 2 years ago

I tried the new beta on my test project and it seems to fix the issue 😍, thank you 👊🏼!

dannyvw commented 2 years ago

After upgrading from 2.7.0.beta-2 to 2.7.0.beta-3 a lot of operations are broken. It gives the following exception "Operation \"\" not found for resource \"ChangePassword\"."

It has possibly something to do with this commit https://github.com/api-platform/core/commit/7c2c3ececea38f6f2a51b027ac0eb1a590cb1c94

XML config for operation

<?xml version="1.0" ?>
<resources xmlns="https://api-platform.com/schema/metadata/resources-3.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="https://api-platform.com/schema/metadata/resources-3.0
           https://api-platform.com/schema/metadata/resources.xsd">
    <resource class="App\Command\ChangePassword" shortName="ChangePassword">
        <operations>
            <operation class="ApiPlatform\Metadata\Patch"
                       input="App\Command\ChangePassword"
                       output="false"
                       status="202"
                       uriTemplate="/change-password"
                       processor="App\State\ChangePasswordProcessor"
            >
                <denormalizationContext>
                    <values>
                        <value name="groups">change_password</value>
                    </values>
                </denormalizationContext>
            </operation>
        </operations>
    </resource>
</resources>

Stacktrace

{
    "@context": "/api/v2/contexts/Error",
    "@type": "hydra:Error",
    "hydra:title": "An error occurred",
    "hydra:description": "Operation \"\" not found for resource \"ChangePassword\".",
    "trace": [
        {
            "namespace": "",
            "short_class": "",
            "class": "",
            "type": "",
            "function": "",
            "file": "/var/www/vendor/api-platform/core/src/Metadata/Resource/ResourceMetadataCollection.php",
            "line": 96,
            "args": []
        },
        {
            "namespace": "ApiPlatform\\Metadata\\Resource",
            "short_class": "ResourceMetadataCollection",
            "class": "ApiPlatform\\Metadata\\Resource\\ResourceMetadataCollection",
            "type": "->",
            "function": "handleNotFound",
            "file": "/var/www/vendor/api-platform/core/src/Metadata/Resource/ResourceMetadataCollection.php",
            "line": 80,
            "args": [
                [
                    "string",
                    ""
                ],
                [
                    "object",
                    "ApiPlatform\\Metadata\\ApiResource"
                ]
            ]
        },
        {
            "namespace": "ApiPlatform\\Metadata\\Resource",
            "short_class": "ResourceMetadataCollection",
            "class": "ApiPlatform\\Metadata\\Resource\\ResourceMetadataCollection",
            "type": "->",
            "function": "getOperation",
            "file": "/var/www/vendor/api-platform/core/src/Serializer/AbstractItemNormalizer.php",
            "line": 709,
            "args": [
                [
                    "string",
                    ""
                ]
            ]
        },
        {
            "namespace": "ApiPlatform\\Serializer",
            "short_class": "AbstractItemNormalizer",
            "class": "ApiPlatform\\Serializer\\AbstractItemNormalizer",
            "type": "->",
            "function": "getFactoryOptions",
            "file": "/var/www/vendor/api-platform/core/src/Serializer/AbstractItemNormalizer.php",
            "line": 488,
            "args": [
                [
                    "array",
                    {
                        "groups": [
                            "string",
                            "change_password"
                        ],
                        "resource_class": [
                            "string",
                            "App\\Command\\ChangePassword"
                        ],
                        "skip_null_values": [
                            "boolean",
                            true
                        ],
                        "operation_type": [
                            "string",
                            "item"
                        ],
                        "iri_only": [
                            "boolean",
                            false
                        ],
                        "request_uri": [
                            "string",
                            "/api/v2/change-password"
                        ],
                        "uri": [
                            "string",
                            "https://localhost/api/v2/change-password"
                        ],
                        "output": [
                            "array",
                            {
                                "class": [
                                    "null",
                                    null
                                ]
                            }
                        ],
                        "types": [
                            "null",
                            null
                        ],
                        "uri_variables": [
                            "array",
                            []
                        ],
                        "api_allow_update": [
                            "boolean",
                            true
                        ],
                        "deep_object_to_populate": [
                            "boolean",
                            true
                        ],
                        "api_denormalize": [
                            "boolean",
                            true
                        ],
                        "cache_key": [
                            "string",
                            "e930a22fa4bfe882fd66037813f771c4"
                        ]
                    }
                ]
            ]
        },
        {
            "namespace": "ApiPlatform\\Serializer",
            "short_class": "AbstractItemNormalizer",
            "class": "ApiPlatform\\Serializer\\AbstractItemNormalizer",
            "type": "->",
            "function": "getAllowedAttributes",
            "file": "/var/www/vendor/symfony/serializer/Normalizer/AbstractObjectNormalizer.php",
            "line": 354,
            "args": [
                [
                    "string",
                    "App\\Command\\ChangePassword"
                ],
                [
                    "array",
                    {
                        "groups": [
                            "string",
                            "change_password"
                        ],
                        "resource_class": [
                            "string",
                            "App\\Command\\ChangePassword"
                        ],
                        "skip_null_values": [
                            "boolean",
                            true
                        ],
                        "operation_type": [
                            "string",
                            "item"
                        ],
                        "iri_only": [
                            "boolean",
                            false
                        ],
                        "request_uri": [
                            "string",
                            "/api/v2/change-password"
                        ],
                        "uri": [
                            "string",
                            "https://localhost/api/v2/change-password"
                        ],
                        "output": [
                            "array",
                            {
                                "class": [
                                    "null",
                                    null
                                ]
                            }
                        ],
                        "types": [
                            "null",
                            null
                        ],
                        "uri_variables": [
                            "array",
                            []
                        ],
                        "api_allow_update": [
                            "boolean",
                            true
                        ],
                        "deep_object_to_populate": [
                            "boolean",
                            true
                        ],
                        "api_denormalize": [
                            "boolean",
                            true
                        ],
                        "cache_key": [
                            "string",
                            "e930a22fa4bfe882fd66037813f771c4"
                        ]
                    }
                ],
                [
                    "boolean",
                    true
                ]
            ]
        },
        {
            "namespace": "Symfony\\Component\\Serializer\\Normalizer",
            "short_class": "AbstractObjectNormalizer",
            "class": "Symfony\\Component\\Serializer\\Normalizer\\AbstractObjectNormalizer",
            "type": "->",
            "function": "denormalize",
            "file": "/var/www/vendor/api-platform/core/src/Serializer/AbstractItemNormalizer.php",
            "line": 353,
            "args": [
                [
                    "array",
                    []
                ],
                [
                    "string",
                    "App\\Command\\ChangePassword"
                ],
                [
                    "string",
                    "json"
                ],
                [
                    "array",
                    {
                        "groups": [
                            "string",
                            "change_password"
                        ],
                        "resource_class": [
                            "string",
                            "App\\Command\\ChangePassword"
                        ],
                        "skip_null_values": [
                            "boolean",
                            true
                        ],
                        "operation_type": [
                            "string",
                            "item"
                        ],
                        "iri_only": [
                            "boolean",
                            false
                        ],
                        "request_uri": [
                            "string",
                            "/api/v2/change-password"
                        ],
                        "uri": [
                            "string",
                            "https://localhost/api/v2/change-password"
                        ],
                        "output": [
                            "array",
                            {
                                "class": [
                                    "null",
                                    null
                                ]
                            }
                        ],
                        "types": [
                            "null",
                            null
                        ],
                        "uri_variables": [
                            "array",
                            []
                        ],
                        "api_allow_update": [
                            "boolean",
                            true
                        ],
                        "deep_object_to_populate": [
                            "boolean",
                            true
                        ],
                        "api_denormalize": [
                            "boolean",
                            true
                        ],
                        "cache_key": [
                            "string",
                            "e930a22fa4bfe882fd66037813f771c4"
                        ]
                    }
                ]
            ]
        },
        {
            "namespace": "ApiPlatform\\Serializer",
            "short_class": "AbstractItemNormalizer",
            "class": "ApiPlatform\\Serializer\\AbstractItemNormalizer",
            "type": "->",
            "function": "denormalize",
            "file": "/var/www/vendor/api-platform/core/src/Serializer/ItemNormalizer.php",
            "line": 77,
            "args": [
                [
                    "array",
                    []
                ],
                [
                    "string",
                    "App\\Command\\ChangePassword"
                ],
                [
                    "string",
                    "json"
                ],
                [
                    "array",
                    {
                        "groups": [
                            "string",
                            "change_password"
                        ],
                        "resource_class": [
                            "string",
                            "App\\Command\\ChangePassword"
                        ],
                        "skip_null_values": [
                            "boolean",
                            true
                        ],
                        "operation_type": [
                            "string",
                            "item"
                        ],
                        "iri_only": [
                            "boolean",
                            false
                        ],
                        "request_uri": [
                            "string",
                            "/api/v2/change-password"
                        ],
                        "uri": [
                            "string",
                            "https://localhost/api/v2/change-password"
                        ],
                        "output": [
                            "array",
                            {
                                "class": [
                                    "null",
                                    null
                                ]
                            }
                        ],
                        "types": [
                            "null",
                            null
                        ],
                        "uri_variables": [
                            "array",
                            []
                        ],
                        "api_allow_update": [
                            "boolean",
                            true
                        ],
                        "deep_object_to_populate": [
                            "boolean",
                            true
                        ],
                        "api_denormalize": [
                            "boolean",
                            true
                        ]
                    }
                ]
            ]
        },
        {
            "namespace": "ApiPlatform\\Serializer",
            "short_class": "ItemNormalizer",
            "class": "ApiPlatform\\Serializer\\ItemNormalizer",
            "type": "->",
            "function": "denormalize",
            "file": "/var/www/vendor/symfony/serializer/Serializer.php",
            "line": 238,
            "args": [
                [
                    "array",
                    []
                ],
                [
                    "string",
                    "App\\Command\\ChangePassword"
                ],
                [
                    "string",
                    "json"
                ],
                [
                    "array",
                    {
                        "groups": [
                            "string",
                            "change_password"
                        ],
                        "resource_class": [
                            "string",
                            "App\\Command\\ChangePassword"
                        ],
                        "skip_null_values": [
                            "boolean",
                            true
                        ],
                        "operation_type": [
                            "string",
                            "item"
                        ],
                        "iri_only": [
                            "boolean",
                            false
                        ],
                        "request_uri": [
                            "string",
                            "/api/v2/change-password"
                        ],
                        "uri": [
                            "string",
                            "https://localhost/api/v2/change-password"
                        ],
                        "output": [
                            "array",
                            {
                                "class": [
                                    "null",
                                    null
                                ]
                            }
                        ],
                        "types": [
                            "null",
                            null
                        ],
                        "uri_variables": [
                            "array",
                            []
                        ],
                        "api_allow_update": [
                            "boolean",
                            true
                        ],
                        "deep_object_to_populate": [
                            "boolean",
                            true
                        ]
                    }
                ]
            ]
        },
        {
            "namespace": "Symfony\\Component\\Serializer",
            "short_class": "Serializer",
            "class": "Symfony\\Component\\Serializer\\Serializer",
            "type": "->",
            "function": "denormalize",
            "file": "/var/www/vendor/api-platform/core/src/Serializer/AbstractItemNormalizer.php",
            "line": 305,
            "args": [
                [
                    "array",
                    []
                ],
                [
                    "string",
                    "App\\Command\\ChangePassword"
                ],
                [
                    "string",
                    "json"
                ],
                [
                    "array",
                    {
                        "groups": [
                            "string",
                            "change_password"
                        ],
                        "resource_class": [
                            "string",
                            "App\\Command\\ChangePassword"
                        ],
                        "skip_null_values": [
                            "boolean",
                            true
                        ],
                        "operation_type": [
                            "string",
                            "item"
                        ],
                        "iri_only": [
                            "boolean",
                            false
                        ],
                        "request_uri": [
                            "string",
                            "/api/v2/change-password"
                        ],
                        "uri": [
                            "string",
                            "https://localhost/api/v2/change-password"
                        ],
                        "output": [
                            "array",
                            {
                                "class": [
                                    "null",
                                    null
                                ]
                            }
                        ],
                        "types": [
                            "null",
                            null
                        ],
                        "uri_variables": [
                            "array",
                            []
                        ],
                        "api_allow_update": [
                            "boolean",
                            true
                        ],
                        "deep_object_to_populate": [
                            "boolean",
                            true
                        ]
                    }
                ]
            ]
        },
        {
            "namespace": "ApiPlatform\\Serializer",
            "short_class": "AbstractItemNormalizer",
            "class": "ApiPlatform\\Serializer\\AbstractItemNormalizer",
            "type": "->",
            "function": "denormalize",
            "file": "/var/www/vendor/api-platform/core/src/Serializer/ItemNormalizer.php",
            "line": 77,
            "args": [
                [
                    "array",
                    []
                ],
                [
                    "string",
                    "App\\Command\\ChangePassword"
                ],
                [
                    "string",
                    "json"
                ],
                [
                    "array",
                    {
                        "groups": [
                            "string",
                            "change_password"
                        ],
                        "resource_class": [
                            "string",
                            "App\\Command\\ChangePassword"
                        ],
                        "skip_null_values": [
                            "boolean",
                            true
                        ],
                        "operation_type": [
                            "string",
                            "item"
                        ],
                        "iri_only": [
                            "boolean",
                            false
                        ],
                        "request_uri": [
                            "string",
                            "/api/v2/change-password"
                        ],
                        "uri": [
                            "string",
                            "https://localhost/api/v2/change-password"
                        ],
                        "output": [
                            "array",
                            {
                                "class": [
                                    "null",
                                    null
                                ]
                            }
                        ],
                        "types": [
                            "null",
                            null
                        ],
                        "uri_variables": [
                            "array",
                            []
                        ],
                        "api_allow_update": [
                            "boolean",
                            true
                        ],
                        "deep_object_to_populate": [
                            "boolean",
                            true
                        ]
                    }
                ]
            ]
        },
        {
            "namespace": "ApiPlatform\\Serializer",
            "short_class": "ItemNormalizer",
            "class": "ApiPlatform\\Serializer\\ItemNormalizer",
            "type": "->",
            "function": "denormalize",
            "file": "/var/www/vendor/symfony/serializer/Serializer.php",
            "line": 238,
            "args": [
                [
                    "array",
                    []
                ],
                [
                    "string",
                    "App\\Command\\ChangePassword"
                ],
                [
                    "string",
                    "json"
                ],
                [
                    "array",
                    {
                        "groups": [
                            "string",
                            "change_password"
                        ],
                        "operation_name": [
                            "string",
                            "_api_/change-password_patch"
                        ],
                        "operation": [
                            "object",
                            "ApiPlatform\\Metadata\\Patch"
                        ],
                        "resource_class": [
                            "string",
                            "App\\Command\\ChangePassword"
                        ],
                        "skip_null_values": [
                            "boolean",
                            true
                        ],
                        "operation_type": [
                            "string",
                            "item"
                        ],
                        "iri_only": [
                            "boolean",
                            false
                        ],
                        "request_uri": [
                            "string",
                            "/api/v2/change-password"
                        ],
                        "uri": [
                            "string",
                            "https://localhost/api/v2/change-password"
                        ],
                        "input": [
                            "array",
                            {
                                "class": [
                                    "string",
                                    "App\\Command\\ChangePassword"
                                ],
                                "name": [
                                    "string",
                                    "ChangePassword"
                                ]
                            }
                        ],
                        "output": [
                            "array",
                            {
                                "class": [
                                    "null",
                                    null
                                ]
                            }
                        ],
                        "types": [
                            "null",
                            null
                        ],
                        "uri_variables": [
                            "array",
                            []
                        ],
                        "api_allow_update": [
                            "boolean",
                            true
                        ],
                        "deep_object_to_populate": [
                            "boolean",
                            true
                        ]
                    }
                ]
            ]
        },
        {
            "namespace": "Symfony\\Component\\Serializer",
            "short_class": "Serializer",
            "class": "Symfony\\Component\\Serializer\\Serializer",
            "type": "->",
            "function": "denormalize",
            "file": "/var/www/vendor/symfony/serializer/Serializer.php",
            "line": 151,
            "args": [
                [
                    "array",
                    []
                ],
                [
                    "string",
                    "App\\Command\\ChangePassword"
                ],
                [
                    "string",
                    "json"
                ],
                [
                    "array",
                    {
                        "groups": [
                            "string",
                            "change_password"
                        ],
                        "operation_name": [
                            "string",
                            "_api_/change-password_patch"
                        ],
                        "operation": [
                            "object",
                            "ApiPlatform\\Metadata\\Patch"
                        ],
                        "resource_class": [
                            "string",
                            "App\\Command\\ChangePassword"
                        ],
                        "skip_null_values": [
                            "boolean",
                            true
                        ],
                        "operation_type": [
                            "string",
                            "item"
                        ],
                        "iri_only": [
                            "boolean",
                            false
                        ],
                        "request_uri": [
                            "string",
                            "/api/v2/change-password"
                        ],
                        "uri": [
                            "string",
                            "https://localhost/api/v2/change-password"
                        ],
                        "input": [
                            "array",
                            {
                                "class": [
                                    "string",
                                    "App\\Command\\ChangePassword"
                                ],
                                "name": [
                                    "string",
                                    "ChangePassword"
                                ]
                            }
                        ],
                        "output": [
                            "array",
                            {
                                "class": [
                                    "null",
                                    null
                                ]
                            }
                        ],
                        "types": [
                            "null",
                            null
                        ],
                        "uri_variables": [
                            "array",
                            []
                        ],
                        "api_allow_update": [
                            "boolean",
                            true
                        ],
                        "deep_object_to_populate": [
                            "boolean",
                            true
                        ]
                    }
                ]
            ]
        },
        {
            "namespace": "Symfony\\Component\\Serializer",
            "short_class": "Serializer",
            "class": "Symfony\\Component\\Serializer\\Serializer",
            "type": "->",
            "function": "deserialize",
            "file": "/var/www/vendor/api-platform/core/src/Symfony/EventListener/DeserializeListener.php",
            "line": 137,
            "args": [
                [
                    "array",
                    []
                ],
                [
                    "string",
                    "App\\Command\\ChangePassword"
                ],
                [
                    "string",
                    "json"
                ],
                [
                    "array",
                    {
                        "groups": [
                            "string",
                            "change_password"
                        ],
                        "operation_name": [
                            "string",
                            "_api_/change-password_patch"
                        ],
                        "operation": [
                            "object",
                            "ApiPlatform\\Metadata\\Patch"
                        ],
                        "resource_class": [
                            "string",
                            "App\\Command\\ChangePassword"
                        ],
                        "skip_null_values": [
                            "boolean",
                            true
                        ],
                        "operation_type": [
                            "string",
                            "item"
                        ],
                        "iri_only": [
                            "boolean",
                            false
                        ],
                        "request_uri": [
                            "string",
                            "/api/v2/change-password"
                        ],
                        "uri": [
                            "string",
                            "https://localhost/api/v2/change-password"
                        ],
                        "input": [
                            "array",
                            {
                                "class": [
                                    "string",
                                    "App\\Command\\ChangePassword"
                                ],
                                "name": [
                                    "string",
                                    "ChangePassword"
                                ]
                            }
                        ],
                        "output": [
                            "array",
                            {
                                "class": [
                                    "null",
                                    null
                                ]
                            }
                        ],
                        "types": [
                            "null",
                            null
                        ],
                        "uri_variables": [
                            "array",
                            []
                        ],
                        "api_allow_update": [
                            "boolean",
                            true
                        ],
                        "deep_object_to_populate": [
                            "boolean",
                            true
                        ]
                    }
                ]
            ]
        },
        {
            "namespace": "ApiPlatform\\Symfony\\EventListener",
            "short_class": "DeserializeListener",
            "class": "ApiPlatform\\Symfony\\EventListener\\DeserializeListener",
            "type": "->",
            "function": "onKernelRequest",
            "file": "/var/www/vendor/symfony/event-dispatcher/Debug/WrappedListener.php",
            "line": 117,
            "args": [
                [
                    "object",
                    "Symfony\\Component\\HttpKernel\\Event\\RequestEvent"
                ],
                [
                    "string",
                    "kernel.request"
                ],
                [
                    "object",
                    "Symfony\\Component\\HttpKernel\\Debug\\TraceableEventDispatcher"
                ]
            ]
        },
        {
            "namespace": "Symfony\\Component\\EventDispatcher\\Debug",
            "short_class": "WrappedListener",
            "class": "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener",
            "type": "->",
            "function": "__invoke",
            "file": "/var/www/vendor/symfony/event-dispatcher/EventDispatcher.php",
            "line": 230,
            "args": [
                [
                    "object",
                    "Symfony\\Component\\HttpKernel\\Event\\RequestEvent"
                ],
                [
                    "string",
                    "kernel.request"
                ],
                [
                    "object",
                    "Symfony\\Component\\HttpKernel\\Debug\\TraceableEventDispatcher"
                ]
            ]
        },
        {
            "namespace": "Symfony\\Component\\EventDispatcher",
            "short_class": "EventDispatcher",
            "class": "Symfony\\Component\\EventDispatcher\\EventDispatcher",
            "type": "->",
            "function": "callListeners",
            "file": "/var/www/vendor/symfony/event-dispatcher/EventDispatcher.php",
            "line": 59,
            "args": [
                [
                    "array",
                    [
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ],
                        [
                            "object",
                            "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
                        ]
                    ]
                ],
                [
                    "string",
                    "kernel.request"
                ],
                [
                    "object",
                    "Symfony\\Component\\HttpKernel\\Event\\RequestEvent"
                ]
            ]
        },
        {
            "namespace": "Symfony\\Component\\EventDispatcher",
            "short_class": "EventDispatcher",
            "class": "Symfony\\Component\\EventDispatcher\\EventDispatcher",
            "type": "->",
            "function": "dispatch",
            "file": "/var/www/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php",
            "line": 154,
            "args": [
                [
                    "object",
                    "Symfony\\Component\\HttpKernel\\Event\\RequestEvent"
                ],
                [
                    "string",
                    "kernel.request"
                ]
            ]
        },
        {
            "namespace": "Symfony\\Component\\EventDispatcher\\Debug",
            "short_class": "TraceableEventDispatcher",
            "class": "Symfony\\Component\\EventDispatcher\\Debug\\TraceableEventDispatcher",
            "type": "->",
            "function": "dispatch",
            "file": "/var/www/vendor/symfony/http-kernel/HttpKernel.php",
            "line": 128,
            "args": [
                [
                    "object",
                    "Symfony\\Component\\HttpKernel\\Event\\RequestEvent"
                ],
                [
                    "string",
                    "kernel.request"
                ]
            ]
        },
        {
            "namespace": "Symfony\\Component\\HttpKernel",
            "short_class": "HttpKernel",
            "class": "Symfony\\Component\\HttpKernel\\HttpKernel",
            "type": "->",
            "function": "handleRaw",
            "file": "/var/www/vendor/symfony/http-kernel/HttpKernel.php",
            "line": 74,
            "args": [
                [
                    "object",
                    "Symfony\\Component\\HttpFoundation\\Request"
                ],
                [
                    "integer",
                    1
                ]
            ]
        },
        {
            "namespace": "Symfony\\Component\\HttpKernel",
            "short_class": "HttpKernel",
            "class": "Symfony\\Component\\HttpKernel\\HttpKernel",
            "type": "->",
            "function": "handle",
            "file": "/var/www/vendor/symfony/http-kernel/Kernel.php",
            "line": 202,
            "args": [
                [
                    "object",
                    "Symfony\\Component\\HttpFoundation\\Request"
                ],
                [
                    "integer",
                    1
                ],
                [
                    "boolean",
                    true
                ]
            ]
        },
        {
            "namespace": "Symfony\\Component\\HttpKernel",
            "short_class": "Kernel",
            "class": "Symfony\\Component\\HttpKernel\\Kernel",
            "type": "->",
            "function": "handle",
            "file": "/var/www/vendor/symfony/runtime/Runner/Symfony/HttpKernelRunner.php",
            "line": 35,
            "args": [
                [
                    "object",
                    "Symfony\\Component\\HttpFoundation\\Request"
                ]
            ]
        },
        {
            "namespace": "Symfony\\Component\\Runtime\\Runner\\Symfony",
            "short_class": "HttpKernelRunner",
            "class": "Symfony\\Component\\Runtime\\Runner\\Symfony\\HttpKernelRunner",
            "type": "->",
            "function": "run",
            "file": "/var/www/vendor/autoload_runtime.php",
            "line": 35,
            "args": []
        },
        {
            "namespace": "",
            "short_class": "",
            "class": "",
            "type": "",
            "function": "require_once",
            "file": "/var/www/public/index.php",
            "line": 5,
            "args": [
                [
                    "string",
                    "/var/www/vendor/autoload_runtime.php"
                ]
            ]
        }
    ]
}
soyuka commented 2 years ago

@dannyvw yeah I backported the fix on inputs/outputs from 3.0. I assume you removed the cache? Can you give me the stack trace for these issues? It should just work as I added isResourceClass everywhere where we try to get back an operation.

dannyvw commented 2 years ago

@soyuka Yes cache is removed. I have added the stack trace to the previous comment.

soyuka commented 2 years ago

It looks quite similar to our test on User:

https://github.com/api-platform/core/blob/2.7/tests/Fixtures/TestBundle/Entity/User.php#L53-L55 or https://github.com/api-platform/core/blob/main/tests/Fixtures/TestBundle/Entity/User.php#L41

There's a new command debug:api could you also give me the operation declaration? (give it in a gist or through slack) I'll try to reproduce.

dannyvw commented 2 years ago

Remove input class if this is the same as the resource class will fix the issue. Thanks for your help!

vincentchalamon commented 2 years ago

PHP: 8.1-fpm-alpine Symfony: 6.1.* API Platform: 3.0-beta

Context

Using the following resource:

#[ApiResource(
    operations: [
        new GetCollection(),
        new Post(),
    ],
)]

The following test fail:

public function testStats(): void
{
    $this->client->request('GET', '/docs.json');
    self::assertResponseIsSuccessful();
    self::assertStringContainsString('/stats', (string) $this->client->getResponse()->getContent());
}

Error

With the following error:

{"type":"https:\/\/tools.ietf.org\/html\/rfc2616#section-10","title":"An error occurred","detail":"Undefined array key \u0022$ref\u0022","trace":[{"namespace":"","short_class":"","class":"","type":"","function":"","file":"\/srv\/api\/vendor\/api-platform\/core\/src\/JsonSchema\/TypeFactory.php","line":159,"args":[]},

Solution

The bug does not occur anymore when reversing the operations order:

#[ApiResource(
    operations: [
        new Post(),
        new GetCollection(),
    ],
)]
dannyvw commented 2 years ago

PHP: 8.1 Symfony: 5.4 API Platform: 3.0.0-beta.1

I have something similar as https://github.com/api-platform/core/issues/4613#issuecomment-1174770854 but changing order in XML configuration does not work for me.

vincentchalamon commented 2 years ago

@dannyvw can you share your XML configuration please?

dannyvw commented 2 years ago

@vincentchalamon It crashed on this file (I removed all context configurations) but i have similar files which are working correct. So it is a bit strange.. Everything works fine in the last 2.7 beta.

<?xml version="1.0" ?>
<resources xmlns="https://api-platform.com/schema/metadata/resources-3.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="https://api-platform.com/schema/metadata/resources-3.0
           https://api-platform.com/schema/metadata/resources.xsd">
    <resource class="App\Entity\User" shortName="User">
        <operations>
            <operation class="ApiPlatform\Metadata\GetCollection" />

            <operation class="ApiPlatform\Metadata\Get" />

            <operation class="ApiPlatform\Metadata\Post" />

            <operation class="ApiPlatform\Metadata\Put" />

            <operation class="ApiPlatform\Metadata\Delete" processor="App\State\UserDeleteProcessor" />
        </operations>
    </resource>
</resources>

With only the delete operation it does not work either. Also not when removing the processor configuration. If i only remove the delete operation in the above configuration it works fine.

<?xml version="1.0" ?>
<resources xmlns="https://api-platform.com/schema/metadata/resources-3.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="https://api-platform.com/schema/metadata/resources-3.0
           https://api-platform.com/schema/metadata/resources.xsd">
    <resource class="App\Entity\User" shortName="User">
        <operations>
            <operation class="ApiPlatform\Metadata\Delete" processor="App\State\UserDeleteProcessor" />
        </operations>
    </resource>
</resources>

I will try to do some more debugging.

Zul3s commented 2 years ago

Hello, No news for my comment : https://github.com/api-platform/core/issues/4613#issuecomment-1168654277. Can i help or more explain something ?

vincentchalamon commented 2 years ago

Hello @Zul3s,

I cannot reproduce your issue. I've juste created a project with a Book entity with a single name property, using the following dependencies:

Can you create a GitHub project to reproduce your bug, please? Also, do you still have the issue with API Platform 2.7-beta.4?

Zul3s commented 2 years ago

Hello @vincentchalamon , Sure, here it is : https://github.com/Zul3s/api-platform_2.7.-_demo In my first comment, i ommit to say parameter metadata backward compatibility layer must be set at false. You can show on my repo, the commit who established the problem.

vincentchalamon commented 2 years ago

@Zul3s Thanks for reporting this issue. A fix has been started here: https://github.com/api-platform/core/pull/4828 I tried it locally, and it seems to solve your issue. Can you try this fix locally too, and confirm me it's ok for you?

vincentchalamon commented 2 years ago

@Zul3s wrong fix, I'm trying to find a better solution. Wait before testing locally, please

vincentchalamon commented 2 years ago

@Zul3s Fix is ready here: https://github.com/api-platform/core/pull/4828 (just pick the first commit) Feel free to try it locally :-)

KDederichs commented 2 years ago

API Platform version(s) affected: 2.7-beta.4 SF 6.1 PHP 8.1

Description
While trying to receive a file using a State Provider, api platform returns the api docs instead of the file.

How to reproduce
Install Vich Uploader like here: https://api-platform.com/docs/main/core/file-upload/ Use FlySystem as Storage

Add this Get operation to the MediaObject new Get(provider: MediaObjectProvider::class, uriTemplate: '/media/{id}'), with:

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\Repository\MediaObjectRepository;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Uid\UuidV6;
use Vich\UploaderBundle\Storage\StorageInterface;

class MediaObjectProvider implements ProviderInterface
{
    public function __construct(private StorageInterface $storage, private MediaObjectRepository $mediaObjectRepository)
    {
    }

    public function provide(Operation $operation, array $uriVariables = [], array $context = [])
    {
        $media = $this->mediaObjectRepository->find(UuidV6::fromString($uriVariables['id']));
        if (!$media || !$stream = $this->storage->resolveStream($media, 'file')) {
            throw new NotFoundHttpException('Media not found');
        }
        $streamResponse = new StreamedResponse(static function () use ($stream) {
            \stream_copy_to_stream($stream, \fopen('php://output', 'wb'));
        });

        return $streamResponse;
    }
}

as provider.

When you then try to access the file via /media/ (after whitelisting the path in the Caddy config), it'll serve the api docs instead of the File

Possible Solution
I assume it's related to the text/html content header you get when trying to access that via browser. Some way to ignore content headers and always serve a certain content would be neat for cases like that.