#supabase #bubble #lowcode #API #graphQL #RPC #SQL
Contexte
Dans le cadre d'une plateforme de gestion énergétique, une formuaire doit permetttre de mettre à jour les informations d'une entreprise et sdes relations :
- le signataire des contrats
- le référent : le contact principal
Afin de décomposer les choses d'une manière élégante côté frontend, la data est scindée en plusieurs petits formulaires :
1 onglet = 1 entité = 1 formulaire
Donc :
- Organisation -> onglet Général (raison_sociale, siret...)
- "référent" inhecté dans le composant Form de l'onglet Référent
- signaaire-> (j'vous le donne en mille) : injecté dans dans le composant Form de l'onglet Signataire
Afin que ce découpage soit bien reflété côté backend, avec des objets séparés, j'ai la solution ultime car conçue pour, j'ai nommé :
Pourquoi graphQL ?
il permet nativement d'imbriquer dans un objet JSON des objets liés JSON.
Et il est natif à Supabase via l'extension pg_graphql développé par...Supabase (incroyable)
Côté graphQL la query t faite ca fait le job propre comme sur le panneau de gauche.
Jusque là tout va bien...
"oui mais"
...Houston : on avait pas prévu ca ! 😬
Oui mais le problème va venir de Bubble qui ne sait PAS interpreter correctement des sous-objects. Il ne tient pas du tout compte que referent et signataire SONT des objets,
pas juste des props "flat".
Sa compréhension erronée le conduit à préfixer les props avec le nom du parent et surtout remonter TOUTES leurs pros au niveau racine, si bien que ces props se confondent parmi celles appartenant à Organisation. Bon pour mettre le foutoir !
Conséquences :
- Bubble ne génère pas les types Referent et Signataire attendus
- on ne peut pas dissocier les objets
- on ne peut pas passer organisation's referent au composant RE.referent
- on ne peut pas passer organisation's signataire au composant RE.signataire
- on est contraint de leur passer organisation complet : le scope est excessif
- on doit faire le tri parmi les props utiles et bruitées dans leurs workflows respectifsfs
Pourquoi ce problème apparait ?
Ce sont les noeuds intermédiaire edges et nodes qui induisent une profondeur trop importante que Bubble s'arrive pas à parser.
La faute à Relay, le système graphQL choisi par Supabase qui suit une convention particulière pour structurer les réponses graphQL, avec des noeuds intermédiaires de metadonnées (pagination, count items, ...). Il y a d'autres conventions moins "riches" (Hasura, Apollo) impliquant moins de hiéararchies et auraient plus être plus compatibles avec Bubble. Mais ce n'est pa interchangeable
.
Quelle solution alternative ?
Il y a 3 solutons pour se passer d'une query graphQL :
- faire 1 +2 calls à l'API Rest et reconsituer le maillage côté frontend (donc régresser)
- écrire une database function SQL invoquable via l'API RPC
- écrire une lambda en code (Deno) invoquable via l'API Function
API Rest ? non je ne veux pas renoncer trop vite aux JSON imbriqués et downsize mes exigences
la seule grande différence entre les 2 API que sont RPC et Functions c'est le dialecte :
- Deno : du code comme Nodejs.
- RPC : une function PL/SQL (du SQL sous steroids)
PL/SQL prévoit une opérateur qui transforme un DB row en un objet JSON standard.
A ce jour je suis pas allé chercher l'équivalent dans la SDK JS, et le PL/SQL est assez naturel.
Donc : RPC
La fonction DB ressemble à ca.
Elle est invoquée directment via un endpoint
POST https://myplatform.com/rest/v1/rpc/get_organisation_full_of_user *
En général (sauf ici) les arguments de la fonction sont formalisés en un simple JSON
que le middleware RPC interne auto-wrappe vers la DB function.
Le endpoint est sécurisé par des RBAC exprimées en SQL avec des GRANT
qui doivent match avec le bearer token frontend passé à la query HTTP
* le choix du nom de fonction est discutable mais là on va se mettre d'accord : on s'en fout.
☝️Mais c'est pas fini ☝️
on n'est toujours pas sorti le c** des ronces :
Bubble n'arrive toujours pas à capter que ce son des objets et imbriqués, donc encore moins capable d'identifier leurs types.
Le SEUL moyen pour lui faire comprendre les choses :
forcer l'objet dans un Array. Oui un bête Array de 1 item.
Là il détecte une liste et estime que l'item dedans se DOIT d'être typé.
ET c'est làààà que Bubble arrive à générer les fameux types tant attendus et qu'on rollback toutes les conséquences néfastes énumérée tout à l'heure.
Oh d'ailleurs voila à quoi ressemble le PL/SQL de la DB Function :