Airtable
Extension payante. Chaque soumission écrit une ligne dans une table Airtable, pour alimenter un suivi opérationnel ou un portail interne.
Ce document décrit ce que le module garantit et ce qu’il refuse. Le guide utilisateur en donne la version courte, dans la section « Écrire dans une base Airtable ».
Ce qui distingue ce module des autres de la série
Il n’écrit pas dans un CRM ni dans une plateforme d’envoi, mais dans une base que des gens ouvrent et lisent. Trois choses en découlent : les valeurs sont celles qu’un humain lirait, les colonnes sont désignées par leur identifiant, et le module convertit lui-même au lieu de laisser Airtable deviner.
Les trois sections qui suivent sont les trois décisions du module.
Les colonnes partent par identifiant, jamais par nom
Airtable accepte les deux dans une écriture. Le nom est ce qu’on lit à l’écran ;
l’identifiant — fldXXXXXXXXXXXXXX — est ce qui ne change pas.
Renommer une colonne est le geste le plus ordinaire du monde dans Airtable. C’est
aussi ce qui casse une association par nom : Airtable répond UNKNOWN_FIELD_NAME,
un refus définitif, et la soumission est perdue — pour un mot changé dans une
interface, par quelqu’un qui ne savait pas qu’un formulaire écrivait là.
L’identifiant est donc ce qui est enregistré, et le nom lisible n’est conservé que pour l’affichage.
Il en va de même pour la base et la table.
Le module convertit ; Airtable ne devine pas
Airtable propose un drapeau typecast qui fait accepter n’importe quelle chaîne
pour n’importe quelle colonne. Pour une liste de choix, il ne se contente pas de
convertir : il crée l’option manquante.
Posé sur un formulaire public, cela veut dire qu’un visiteur qui tape ce qu’il veut dans un champ libre associé à une liste de choix ajoute ce qu’il veut aux options de la base du client. Ce n’est plus écrire une ligne, c’est modifier le schéma — depuis l’extérieur, et sans que personne ne l’ait demandé.
Le drapeau reste donc éteint. La conversion se fait ici, à partir du type de la colonne, enregistré avec l’association au moment du réglage :
| Type de colonne | Ce qui est envoyé |
|---|---|
| Texte, texte long, courriel, URL, téléphone, liste simple | la valeur telle quelle |
| Nombre, montant, pourcentage, note, durée | un nombre — la virgule décimale et les espaces de groupement sont lus |
| Case à cocher | vrai, sauf non, no, false, off, 0 |
| Liste multiple | la valeur redécoupée sur les virgules |
| Date | AAAA-MM-JJ — la forme JJ/MM/AAAA est reconnue avant tout le reste |
| Date et heure | ISO 8601 en temps universel |
Ce qui ne se convertit pas est omis, jamais deviné. Omettre coûte une colonne
vide ; deviner coûte un refus 422 sur l’enregistrement entier, car Airtable ne
garde pas les champs valides d’une requête dont un champ ne l’est pas. Une date mal
lue ferait donc perdre la soumission complète plutôt qu’une colonne.
Une valeur vide n’est pas envoyée non plus : sur une mise à jour, elle écraserait ce que la ligne portait déjà.
Si toutes les valeurs sont omises, rien n’est écrit : une ligne vide dans la base ne renseigne personne et se confond avec une panne.
La clé de fusion est ce qui rend l’écriture idempotente
Sans clé, chaque envoi crée. Une requête dont la réponse se perd en route est rejouée, et laisse deux lignes dans la base. La clé unique locale n’y peut rien : le premier appel a bien abouti chez Airtable.
Avec une clé, l’écriture est un PATCH portant performUpsert : Airtable cherche
la ligne sur cette colonne, la met à jour si elle existe, la crée sinon.
La clé n’est donc pas une option de confort, et le panneau le dit en toutes lettres plutôt que de laisser découvrir les doublons. Elle doit être une colonne associée — fusionner sur une colonne qu’on n’écrit pas ne retrouverait jamais rien — et d’un type qu’Airtable admet : texte, texte long, courriel, URL, téléphone, nombre, liste simple ou multiple, date. Une case à cocher ou une colonne calculée fait refuser la requête entière, et n’est donc pas proposée.
Quand la clé est réglée mais vide sur une soumission, le module crée au lieu de fusionner, et l’écrit au journal : fusionner sur une colonne vide retrouverait la première ligne dont cette colonne est vide, c’est-à-dire n’importe laquelle.
L’écran de connexion montre le nombre d’enregistrements créés plutôt que fusionnés. C’est le chiffre qu’on vient chercher quand une base se remplit de doublons.
Un jeton personnel plutôt qu’une application
Les deux sont possibles ; l’écran recommande le premier, et ce n’est pas par facilité.
Un jeton d’accès personnel se crée en une minute sur airtable.com/create/tokens,
n’expire pas, et porte les portées qu’on lui donne — ici data.records:write et
schema.bases:read. Il n’y a rien à renouveler.
Un jeton OAuth dure une heure et se renouvelle, en faisant tourner le jeton de rafraîchissement : Airtable invalide l’ancien couple dès qu’il en rend un nouveau. C’est précisément le piège, et il est détaillé ci-dessous.
OAuth reste proposé pour le cas où il est imposé : un jeton qui ne doit pas appartenir au compte d’une personne en particulier, parce que cette personne quittera l’entreprise avant le site.
Le renouvellement ne se fait jamais à deux
Deux tâches qui renouvellent en même temps produisent ceci : la première obtient un couple neuf et l’enregistre ; la seconde présente le jeton qu’elle avait lu avant, déjà mort, se voit refuser — et effacerait le couple valide que la première venait d’enregistrer.
L’autorisation serait perdue sans retour. Aucune reprise ne la retrouve : il faut qu’un humain revienne réautoriser. Et cela arriverait précisément quand le site marche bien, puisqu’il faut deux soumissions rapprochées pour y parvenir.
Le renouvellement est donc pris sous un verrou, et ce verrou est une insertion tranchée par la clé unique de la table des options — jamais une lecture suivie d’une écriture, qui laisserait entre les deux l’intervalle où l’autre processus lit la même chose. C’est le procédé qu’emploie WordPress lui-même pour verrouiller ses mises à jour.
Celui qui n’obtient pas le verrou ne se met pas à attendre : il relit la connexion, et si l’autre a terminé, le jeton est frais. Sinon il renonce pour cette fois, et la reprise s’en charge. Faire dormir une tâche planifiée immobiliserait le processus qui exécute toutes les autres.
Un jeton personnel ne passe pas par là : il n’a ni rotation, ni verrou, ni panne possible.
PKCE, qu’Airtable rend obligatoire
Les autres intégrations de cette série s’en passent. Airtable l’exige : la demande d’autorisation porte l’empreinte SHA-256 d’un secret tiré au hasard, et l’échange porte le secret lui-même. Un code d’autorisation intercepté ne vaut donc rien sans ce secret, qui n’a jamais quitté ce serveur.
Le vérificateur est conservé dans le même éphémère nominatif que l’état, et détruit à l’usage.
Le secret client, lui, voyage dans l’en-tête Authorization: Basic — c’est la forme
qu’Airtable impose ; posé dans le corps, il est refusé.
Cinq requêtes par seconde et par base
C’est la limite documentée, et elle est basse. Un envoi n’en consomme qu’une — deux
au plus avec un renouvellement de jeton. Un 429 demande d’attendre trente
secondes ; la reprise attend une minute, puis cinq, puis trente. Ce n’est pas une
panne, c’est une file d’attente.
Ce qui n’est pas tenté, et ce qui est rejoué
Rien n’est programmé sans base, sans table, sans colonne associée, sans connexion, ou si la condition du formulaire n’est pas remplie. Une soumission marquée indésirable ou mise à la corbeille ne part pas.
Les refus définitifs ne sont pas rejoués : colonne inconnue, option de liste absente, type incompatible, table supprimée, jeton sans la portée d’écriture. Les rejouer donnerait trois fois le même non.
Les 429 et les 5xx le sont, à 1, 5 puis 30 minutes.
Une panne d’Airtable ne bloque jamais la soumission. Elle est enregistrée, confirmée au visiteur et notifiée par courriel avant que ce module ne soit sollicité.
Renvoyer
Le bouton de renvoi rejoue la même écriture : avec une clé, il met la ligne à jour ; sans clé, il en crée une seconde. L’écran le dit avant qu’on appuie.
Ce que le journal ne contient pas
Ni la requête, ni la réponse. La première porte les valeurs de la soumission, et Airtable rend dans la seconde l’enregistrement tel qu’il l’a écrit. Les consigner ferait du journal une seconde copie, qui s’en irait dans les sauvegardes et les exports — où elle se lirait comme une trace technique alors qu’elle décrit une personne.
L’adresse, elle, est consignée en entier : une base et une table ne sont pas des données personnelles, et ce sont les deux premières choses à vérifier quand rien n’arrive.
Schéma
slf_airtable_records : une ligne par soumission destinée à Airtable, avec la base,
la table, l’identifiant de l’enregistrement rendu, s’il a été créé ou fusionné,
l’état, le motif du dernier problème et le nombre de tentatives.
La connexion vit dans une option : la sorte de connexion, l’identifiant client et l’identifiant de compte en clair — ce ne sont pas des secrets —, les jetons et le secret client chiffrés.
Effacer une soumission efface sa ligne de suivi et son journal. La ligne déjà écrite dans Airtable, elle, reste : elle appartient à la base du client, et la supprimer d’ici serait décider à sa place — sur une base dont ce module n’a même pas la portée de lecture.
Ce que la V1 ne fait pas
Pas de lecture d’enregistrements, pas de suppression, pas de pièce jointe, pas de lien vers une autre table, pas de colonne calculée, pas de synchronisation en sens inverse.
Une pièce jointe se décrit par une adresse publiquement téléchargeable, et un lien par l’identifiant d’un enregistrement qu’il faudrait d’abord chercher : les deux demandent davantage que ce qu’un formulaire a à donner. Un formulaire écrit ; il ne tient pas la base.
