API Links

API Links

Les API Links : Simplifier la Navigation dans vos APIs REST

Introduction

Lorsque vous développez une API REST moderne, l’un des défis majeurs est de fournir aux clients de l’API les liens vers les actions disponibles sur chaque ressource. Faut-il permettre à l’utilisateur de modifier cette ressource ? De la supprimer ? D’effectuer des actions spécifiques ?

Dans notre projet, nous avons développé un système innovant appelé API Links qui résout élégamment ce problème en générant automatiquement les liens d’actions disponibles selon les permissions de l’utilisateur.

Le Problème à Résoudre

Dans une API REST classique, le client doit :

  • Connaître toutes les routes disponibles
  • Gérer les permissions côté frontend
  • Faire des requêtes supplémentaires pour vérifier les droits

Cela crée une forte couplage entre le frontend et le backend, et rend difficile l’évolution de l’API.

Notre Solution : Le Système API Links

Vue d’Ensemble

Le système API Links génère automatiquement les liens vers les actions disponibles pour chaque ressource, en tenant compte des permissions de l’utilisateur connecté. Ces liens sont ajoutés à la réponse JSON-LD sous la propriété hydra:links.

Architecture du Système

Le système se compose de plusieurs composants clés :

1. Configuration Déclarative (YAML)

Chaque entité peut avoir ses liens définis dans un fichier YAML dans le dossier /config/api_links/. Voici un exemple pour l’entité Profile :

YAML
App\Entity\Profile:
  profile:edit:
    route: _api_/v2/startup_requests/{id}{._format}_patch
    voterAttribute: !php/const App\Security\Voter\StartupVoter::EDIT
  profile:delete:
    route: delete_profile
    voterAttribute: !php/const App\Security\Voter\StartupVoter::DELETE
  benchmarks:list:
    route: api_benchmark_results_get_collection
    voterAttribute: !php/const App\Security\Voter\BenchmarkVoter::SEARCH

2. Lecteur de Configuration

Le HydraLinksConfigurationReader parcourt automatiquement tous les fichiers YAML du dossier api_links et compile la configuration :

PHP
public function getLinksConfiguration(): array
{
    $linksConfiguration = [];
    $finder = new Finder();
    $finder->in($projectDir . '/config/api_links')->files()->name('*.yaml');

    foreach ($finder as $file) {
        $config = Yaml::parseFile($file->getRealPath(), Yaml::PARSE_CONSTANT);
        foreach ($config as $key => $value) {
            $linksConfiguration[$key] = $value;
        }
    }

    return $linksConfiguration;
}

3. Générateur de Liens

Le HydraLinksGenerator est le cœur du système. Il :

  • Vérifie si l’entité a des liens configurés
  • Contrôle les permissions via les Voters Symfony
  • Génère les URLs des actions autorisées
PHP
public function generate($object): array
{
    $resourceClass = str_replace("Proxies\\__CG__\\", '', $object::class);
    $links = [];

    if (isset($this->apiLinksConfig[$resourceClass])) {
        foreach ($this->apiLinksConfig[$resourceClass] as $name => $config) {
            if (isset($config['voterAttribute']) && 
                $this->authorizationChecker->isGranted($config['voterAttribute'], $object)) {
                $links[$name] = $this->generateLink($object, $config);
            }
        }
    }

    return $links;
}

4. Normalizer pour l’Injection Automatique

Le HydraLinksNormalizer intercepte la sérialisation des entités et ajoute automatiquement les liens à la réponse JSON :

PHP
public function normalize(mixed $object, string $format = null, array $context = []): array
{
    $data = $this->normalizer->normalize($object, $format, $context);
    
    if($this->canNormalizeWithLinks($object, $context)) {
        $links = $this->hydraLinksGenerator->generate($object);
        $data['hydra:links'] = $links;
    }

    return $data;
}

Exemples Concrets

Configuration d’un Club

YAML
App\Entity\Club:
  club:edit:
    route: _api_/v2/clubs/{id}{._format}_patch
    voterAttribute: !php/const App\Security\Voter\ClubVoter::EDIT
  club:delete:
    route: _api_/v2/clubs/{id}{._format}_delete
    voterAttribute: !php/const App\Security\Voter\ClubVoter::DELETE
  club:invitation:
    route: _api_/v2/invitations{._format}_post
    voterAttribute: !php/const App\Security\Voter\ClubVoter::INVITATION

Réponse API Résultante

Quand un utilisateur fait une requête GET sur /api/clubs/123?withApiLinks=true, il recevra :

JSON
{
  "@context": "/api/contexts/Club",
  "@id": "/api/clubs/123",
  "@type": "Club",
  "id": 123,
  "name": "Mon Club",
  "hydra:links": {
    "club:edit": "/api/clubs/123",
    "club:invitation": "/api/invitations"
  }
}

Note : Le lien club:delete n’apparaît pas car l’utilisateur n’a pas les permissions nécessaires.

Avantages du Système

1. Découplage Frontend/Backend

Le frontend n’a plus besoin de connaître les règles de permissions – il suffit de vérifier la présence des liens.

2. Sécurité Renforcée

Les permissions sont contrôlées côté serveur via les Voters Symfony, garantissant la cohérence.

3. Évolutivité

Ajouter de nouvelles actions ne nécessite que la mise à jour du fichier YAML correspondant.

4. Standard JSONLD/Hydra

Le système respecte les standards web sémantiques, facilitant l’interopérabilité.

5. Performance

Les liens sont générés en une seule passe lors de la sérialisation, sans requêtes supplémentaires.

Utilisation Côté Client

Activation des Links

Pour activer les API Links, ajoutez le paramètre withApiLinks=true à vos requêtes :

GET /api/profiles/456?withApiLinks=true

Traitement Frontend

Côté frontend, vous pouvez facilement vérifier les actions disponibles :

TypeScript
// Vérifier si l'édition est autorisée
const canEdit = response['hydra:links']?.['profile:edit'] !== undefined;

// Construire dynamiquement les boutons d'action
const actions = Object.keys(response['hydra:links'] || {});

Intégration dans Symfony

Le système s’intègre naturellement dans Symfony via :

  • Compiler Pass : Charge la configuration au build
  • Dependency Injection : Injecte la configuration dans les services
  • Event System : S’appuie sur les normalizers Symfony

Conclusion

Le système API Links représente une approche moderne et élégante pour gérer les actions disponibles dans une API REST. En combinant la configuration déclarative, les Voters Symfony et les standards web sémantiques, il offre une solution robuste qui simplifie le développement tout en améliorant la sécurité.

Cette approche nous a permis de :

  • Réduire le code de gestion des permissions côté frontend
  • Améliorer la maintenabilité de l’API
  • Offrir une meilleure expérience développeur
  • Respecter les standards industriels

Le système API Links illustre parfaitement comment une architecture bien pensée peut transformer un problème complexe en une solution élégante et réutilisable.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *