7 - Les extensions (limiter la sortie des données)

Dans le cadre d'un point d'API classique lié à une entity, les extensions suivent plus ou moins la même philosophie qu'un filters à une différence majeur:

  • Le filtre est demandé par le client pendant sa requête

  • L'extension est placé automatiquement par le back selon X ou Y facteurs.

On s'en sert principalement lors d'un GET pour limiter les données renvoyés (voir https://api-platform.com/docs/symfony/security/#filtering-collection-according-to-the-current-user-permissionsarrow-up-right)

Exemple pratique

Prenons un exemple simple:

Je veux rajouter une extension sur le listing de mes utilisateurs:

  • Si admin ou agent: Peut voir tout le monde

  • Si user: les autres "user" classique ne ressortent pas, seulement les admin / agents


Comme souvent, ApiPlatforme nous mache le travail via des interfaces:

  • ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface Pour limiter les GetCollection

  • ApiPlatform\Doctrine\Orm\Extension\QueryItemExtensionInterface Pour limiter les Get

Créons donc notre extensions avec ces deux Interface:

<?php declare(strict_types=1);

namespace App\Api\Extensions;

use ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
use ApiPlatform\Doctrine\Orm\Extension\QueryItemExtensionInterface;
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use ApiPlatform\Metadata\Operation;
use Doctrine\ORM\QueryBuilder;

class UsersListingExtension implements QueryCollectionExtensionInterface, QueryItemExtensionInterface

{
    public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, array $context = []): void
    {
        // TODO: Implement applyToCollection() method.
    }

    public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, ?Operation $operation = null, array $context = []): void
    {
        // TODO: Implement applyToItem() method.
    }
}

Les interfaces arrivent avec leur méthode pour filter, pour le reste, ça va être très similaire au Filtres.

Pour me simplifier la vie, je fais passer ces deux méthodes dans une seule fonction qui s'occupera de tout filter pour moi.

La première étape est de vérifier la ressource demandé par ApiPlatform. En effet, le fonctionnement de base est le même que le serializer de Symfony:

Il va tenter de passer dans toutes les Extensions connues et c'est à nous de spécifier si l'extension s'applique pour la requête en cours

Ici, si on ne fait pas de requête sur notre User, on skip.

Maintenant un peu de logique, on vérifie le role de notre User courant:

Si on est un Admin ou un Agent, pas besoin de limiter la liste des utilisateurs, l'extension ne fera pas effet.

Il ne nous reste que la query à modifié pour filter et ne laisser sortir que le agents avec le role admin ou le role agent.

Et voilà, les admins continuent de voir tout le monde tandis qu'un simple user ne peut pas !

Grace à cela, vos utilisateurs sont en sécurité.

Last updated