The international conference on the API Platform Framework
The API Platform Conference 2024 is happening soon, and it's close to selling out.
API Platform 4, Caddy web server, Xdebug, AI... Enjoy two days of inspiring talks with our friendly community and our amazing speakers.
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.
<?php
// api/src/Entity/Person.php
namespace App\Entity;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use App\State\PersonProvider;
use App\Uuid;
#[ApiResource(provider: PersonProvider::class)]
final class Person
{
/**
* @var Uuid
*/
#[ApiProperty(identifier: true)]
public $code;
// ...
}
# api/config/api_platform/resources/Person.yaml
properties:
App\Entity\Person:
code:
identifier: true
resource:
App\Entity\Person:
provider: App\State\PersonProvider
<properties xmlns="https://api-platform.com/schema/metadata/properties-3.0">
<property resource="App\Entity\Person" name="code" identifier="true"/>
</properties>
<resources xmlns="https://api-platform.com/schema/metadata/resources-3.0">
<resource class="App\Entity\Person" provider="App\State\PersonProvider" />
</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 Provider
for the Person
entity:
<?php
namespace App\State;
use App\Entity\Person;
use ApiPlatform\State\ProviderInterface;
use App\Uuid;
final class PersonProvider implements ProviderInterface
{
/**
* {@inheritDoc}
*/
public function provide(Operation $operation, array $uriVariables = [], array $context = [])
{
// Our identifier is:
// $uriVariables['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:
// $uriVariable['code']->getTimestamp()
}
}
To cover this use case, we need to transform
the identifier to an instance of our App\Uuid
class.
This case is covered by an URI variable transformer:
<?php
namespace App\Identifier;
use ApiPlatform\Api\UriVariableTransformerInterface;
use ApiPlatform\Exception\InvalidUriVariableException;
use App\Uuid;
final class UuidUriVariableTransformer implements UriVariableTransformerInterface
{
/**
* Transforms a uri variable value.
*
* @param mixed $value The uri variable value to transform
* @param array $types The guessed type behind the uri variable
* @param array $context Options available to the transformer
*
* @throws InvalidUriVariableException Occurs when the uriVariable could not be transformed
*/
public function transform($value, array $types, array $context = []) {
try {
return Uuid::fromString($data);
} catch (InvalidUuidStringException $e) {
throw new InvalidUriVariableException($e->getMessage());
}
}
/**
* Checks whether the given uri variable is supported for transformation by this transformer.
*
* @param mixed $value The uri variable value to transform
* @param array $types The types to which the data should be transformed
* @param array $context Options available to the transformer
*/
public function supportsTransformation($value, array $types, array $context = []): bool
{
return is_a($type, Uuid::class, true);
}
}
Tag this service as an api_platform.uri_variables.transformer
:
services:
App\Identifier\UuidUriVariableTransformer:
tags:
- { name: api_platform.uri_variables.transformer }
<service id="App\Identifier\UuidUriVariableTransformer" class="App\Identifier\UuidUriVariableTransformer" public="false">
<tag name="api_platform.uri_variables.transformer" />
</service>
Your PersonProvider
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
// api/src/Entity/Person.php
namespace App\Entity;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use App\Uuid;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
#[ApiResource]
final class Person
{
#[ORM\Id, ORM\Column, ORM\GeneratedValue]
#[ApiProperty(identifier: false)]
private ?int $id = null;
/**
* @var Uuid
*/
#[ORM\Column(type: 'uuid', unique: true)]
#[ApiProperty(identifier: 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)\Symfony\Component\Uid\Ulid
(see UlidNormalizer)\Symfony\Component\Uid\Uuid
(see UuidNormalizer)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