Api-Platform with Symfony: Severe performance issues when using basic identifiers

I’m having a major problem with my Symfony project that uses Api-Platform. When I use basic identifiers as shown in the docs, the PATCH action is super slow. It takes about 30,600 seconds to finish!

The logs show that the denormalization process is causing this. I’ve set up my OrganizationPlainIdentifierDenormalizer class like this:

class OrganizationPlainIdentifierDenormalizer implements DenormalizerInterface, DenormalizerAwareInterface
{
    use DenormalizerAwareTrait;

    public function __construct(private EntityManagerInterface $entityManager) {}

    public function denormalize($data, $class, $format = null, array $context = [])
    {
        foreach (['clients', 'owners', 'resourceServers'] as $field) {
            if (isset($data[$field])) {
                $data[$field] = array_map(fn($item) => $this->entityManager->getReference($this->getEntityClass($field), $item['id']), $data[$field]);
            }
        }

        return $this->denormalizer->denormalize($data, $class, $format, $context + [__CLASS__ => true]);
    }

    private function getEntityClass($field)
    {
        $map = [
            'clients' => Client::class,
            'owners' => Person::class,
            'resourceServers' => ResourceServer::class,
        ];
        return $map[$field];
    }

    // Other methods remain the same
}

Does anyone know how to make this faster? I’m open to any suggestions or tricks to boost the performance. Thanks!

have u tried using eager loading for those related entities? might help speed things up. also, consider caching if possible. another idea: maybe batch processing could work better for large datasets. hope this helps!

I encountered a similar issue in one of my projects. The main culprit was likely the repeated database queries for each item in the arrays. To optimize this, I’d suggest implementing a bulk fetch strategy.

Instead of fetching references one by one, collect all the IDs for each entity type, then perform a single query to fetch them in bulk. This significantly reduced the number of database calls in my case.

Also, consider implementing a custom denormalizer for each entity type. This allows for more fine-grained control over the denormalization process and can lead to better performance.

Lastly, if possible, try to minimize the amount of data being sent in the PATCH request. Only including the necessary fields can greatly reduce processing time.

I’ve dealt with similar performance issues in API Platform before. One thing that really helped was implementing a custom data provider. This way, you can optimize the query to fetch only the data you need, reducing unnecessary database calls.

Another approach that worked wonders for me was using DTOs (Data Transfer Objects) instead of directly exposing entity objects. This gives you more control over what data is serialized and deserialized, potentially reducing the load on your system.

Have you considered using composite identifiers instead of basic ones? In some cases, this can lead to better performance, especially with complex relationships.

Lastly, don’t underestimate the power of proper indexing in your database. It’s often overlooked, but can make a huge difference in query performance, especially for operations like PATCH that involve lookups.