v2.5 Identifiers

Identifiers

Every item operation has an identifier in its URL. Although this identifier is usually a number, it can also be an UUID, a date, or the type of your choice. To help with your development experience, we introduced an identifier normalization process.

Custom Identifier Normalizer

In the following chapter, we’re assuming that App\Uuid is a project-owned class that manages a time-based UUID.

Let’s say you have the following class, which is identified by a UUID type. In this example, UUID is not a simple string but an object with many attributes.

```php use ApiPlatform\Core\Annotation\ApiResource; use ApiPlatform\Core\Annotation\ApiProperty; use App\Uuid;

/**

  • @ApiResource / final class Person { /*

    • @var Uuid
    • @ApiProperty(identifier=true) */ public $code;

    // … }


```xml
<resources xmlns="https://api-platform.com/schema/metadata">
    <resource class="App\EntityPerson">
        <property name="code" identifier="true"/>
    </resource>
</resources>

Once registered as an ApiResource, having an existing person, it will be accessible through the following URL: /people/110e8400-e29b-11d4-a716-446655440000. Note that the property identifying our resource is named code.

Let’s create a DataProvider for the Person entity:

<?php
namespace App\DataProvider;

use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
use App\Entity\Person;
use App\Uuid;

final class PersonDataProvider implements ItemDataProviderInterface, RestrictedDataProviderInterface
{
    /**
     * {@inheritdoc}
     */
    public function getItem(string $resourceClass, $identifiers, string $operationName = null, array $context = [])
    {
        // Our identifier is:
        // $identifiers['code']
        // although it's a string, it's not an instance of Uuid and we wanted to retrieve the timestamp of our time-based uuid:
        // $identifiers['code']->getTimestamp()
    }

    /**
     * {@inheritdoc}
     */
    public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
    {
        return $resourceClass === Person::class;
    }
}

To cover this use case, we need to denormalize the identifier to an instance of our App\Uuid class. This case is covered by an identifier denormalizer:

<?php
namespace App\Identifier;

use ApiPlatform\Core\Exception\InvalidIdentifierException;
use App\Uuid;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;

final class UuidNormalizer implements DenormalizerInterface
{
    /**
     * {@inheritdoc}
     */
    public function denormalize($data, $class, $format = null, array $context = [])
    {
        try {
            return Uuid::fromString($data);
        } catch (InvalidUuidStringException $e) {
            throw new InvalidIdentifierException($e->getMessage());
        }
    }

    /**
     * {@inheritdoc}
     */
    public function supportsDenormalization($data, $type, $format = null)
    {
        return is_a($type, Uuid::class, true);
    }
}

Tag this service as an api_platform.identifier.denormalizer:

```yaml services: App\Identifier\UuidNormalizer: tags: - { name: api_platform.identifier.denormalizer } ```
  <service id="App\Identifier\UuidNormalizer" class="App\Identifier\UuidNormalizer" public="false">
      <tag name="api_platform.identifier.denormalizer" />
  </service>

Your PersonDataProvider will now work as expected!

Changing Identifier in a Doctrine Entity

If your resource is also a Doctrine entity and you want to use another identifier other than the Doctrine one, you have to unmark it:

<?php
namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiProperty;
use App\Uuid;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ApiResource
 */
final class Person
{
    /**
     * @var int
     * @ApiProperty(identifier=false)
     *
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;
    
    /**
     * @var Uuid
     * @ApiProperty(identifier=true)
     * @ORM\Column(type="uuid", unique=true)
     */
    public $code;
    
    // ...
}

Supported Identifiers

API Platform supports the following identifier types:

You can also help us improve the documentation of this page.

Made with love by

Les-Tilleuls.coop can help you design and develop your APIs and web projects, and train your teams in API Platform, Symfony, Next.js, Kubernetes and a wide range of other technologies.

Learn more

Copyright © 2023 Kévin Dunglas

Sponsored by Les-Tilleuls.coop