Le blog

Comment faire cohabiter des ressources portant le même nom, depuis deux domaines différents avec API Platform ?

Publié le 23 mars 2022

Si vous avez suivi nos récentes actualités, vous savez que chez Les-Tilleuls.coop, nous sommes friands des patterns tactiques du DDD ! Si vous ne l’avez pas encore fait, je vous invite d’ailleurs à aller regarder l’excellente conférence de nos deux coopérateurs Robin Chalas et Mathias Arlaud sur la chaîne YouTube de l’AFUP.

Dans cette approche structurelle, il faut découper et hiérarchiser notre code en trois couches principales : Infrastructure, Domain & Application (des variations avec une couche Représentation existent, mais ce n’est pas le sujet ici).

Or une même idée peut être exprimée et définie dans plusieurs domaines, par exemple, si je conçois un module de forum ainsi qu’un module de discussion en temps réel. Dans mes deux domaines, je possèderai un modèle public dont la classe est nommée `Message`, chacun utilisant son propre espace de nom : `App\Domain\Forum\Model\Message` et `App\Domain\Chat\Model\Message`.

Pour exposer ces deux modèles à travers API Platform, j’ajoute donc l’attribut au-dessus de chacune des classes, et je m’assure que le mapping observe bien les deux répertoires. Mais voici le résultat obtenu lorsqu’on recharge la documentation OpenAPI :

L’une des deux ressources `Message` est complètement ignorée !

Vraiment ? Ou bien seule la documentation est impactée ?

`bin/console debug:router`

Visiblement, non. API Platform a ignoré l’une de mes ressources. Oui mais laquelle ?

Pour y voir plus clair, j’ajoute un préfixe sur mes ressources :

Vérifions !


Nous pouvons observer que la ressource venant du domaine Chat n’est pas prise en compte. L’ordre de chargement des ressources a son rôle à jouer, il est effectué dans l’ordre de déclaration du mapping dans le fichier `/config/packages/api_platform.yaml`, puis dans l’ordre alphabétique. Chez moi, c’est ma ressource de forum qui est conservée.

Très bien, mais j’aimerais conserver les deux ! Comment faire ?

Ce qui pose problème ici, c’est qu’API Platform organise nos ressources en s’appuyant sur le nom de la classe (et pas son FQCN), puis il définit les opérations. Si je ne précise rien du tout dans l’attribut `ApiResource`, le nom de mes opérations seront ‘get’, ‘put’, ‘patch’, ‘delete’ pour la ressource, et ‘get’, ‘post’ pour la collection. On en déduit donc que pour nos deux ressources, l’une d’elle phagocyte l’autre.

La première chose possible est alors de définir manuellement les routes nécessaires pour la ressource qui n’est pas visible. Celle du chat pour moi :

Voyons le résultat :

Ligne 4 !! J’ai ma route youhou ! Je n’ai plus qu’à répéter l’opération, voyons le résultat dans Swagger UI : 

Trop bien !

Bon par souci d’homogénéité et pour éviter d’avoir à réfléchir à l’ordre de priorité entre mes ressources, il serait de bon ton d’harmoniser mes déclarations de ressource. Je vais donc systématiquement déclarer toutes mes opérations. C’est un peu pénible, mais préférable sur le long terme.

source: freepik

La Product Owner m’appelle et ça ne va pas du tout, il faut absolument séparer les deux groupes de routes ! Qu'à cela ne tienne, à cœur vaillant rien d’impossible ! :)

La solution difficile, ce serait de surcharger ou décorer les factory de documentation. Heureusement il existe un bijou caché (bon pas vraiment, mais pas mis en lumière disons :p) la propriété shortName. C’est elle qui est utilisée pour les IRI, les tags OpenAPI, les noms des ressources, faire le café (c’est faux).

Revenons en arrière, et appliquons cette modification à notre modèle de chat :

Nous obtenons de manière complètement indépendante nos endpoints de forum et de chat.

Et le Swagger UI ?

Superbe :)
Je vais pouvoir rassurer ma PO :D

Merci de m’avoir lu !

Envie d’en apprendre plus sur API Platform ?
Rendez-vous sur notre catalogue de formations :)

Le blog

Pour aller plus loin