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.
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.
/**
@ApiResource / final class Person { /*
// … }
```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
:
<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!
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;
// ...
}
API Platform supports the following identifier types:
scalar
(string, integer)\DateTime
(uses the symfony DateTimeNormalizer
internally, see DateTimeIdentifierNormalizer)\Ramsey\Uuid\Uuid
(see UuidNormalizer)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