Imports et exports
Un module n’écrit pas son propre import. Le noyau en fournit un, et il impose une chose que personne n’impose spontanément à soi-même : un essai à blanc avant toute écriture.
Sortir
Toute liste s’exporte, sans qu’aucun module n’ait rien à déclarer :
curl -H "Authorization: Bearer $TOKEN" \ "/api/v1/library_title/export?format=csv"id,name,author,isbn,published_year,genre,summary,cover1,Dune,Frank Herbert,9780441013593,1965,fiction,"A desert planet, a spice, and an empire...",8Quatre formats : csv, json, jsonl, xml. L’export passe par la session filtrée :
un lecteur n’exporte que ce qu’il a le droit de lire, et une ligne interdite n’est pas
« masquée », elle n’existe pas dans le fichier.
Les colonnes de tenue de livres (version, created_by_id, deleted_at…) ne sortent pas.
Ce n’est pas de la coquetterie : l’import que cet export sert à nourrir les refuse, donc
les livrer casserait la boucle. id reste, parce que c’est par lui qu’une ligne modifiée
retrouve sa fiche.
Pour choisir, et fixer l’ordre :
"/api/v1/library_title/export?format=csv&fields=isbn,name,genre"isbn,name,genre9780441013593,Dune,fictionUn nom inconnu est refusé plutôt qu’ignoré :
422 {"detail":"unknown export field(s): titel"}Une faute de frappe qui exporte une colonne vide ressemble exactement à un modèle qui ne contient rien.
Rentrer
L’import est un plan qu’on approuve, pas un bouton. Quatre états, et on ne saute aucun :
analysé → approuvé → (essai à blanc) → exécuté1. Déposer. Le fichier monte, le noyau le lit et propose une correspondance colonnes →
champs. mode=ai la fait deviner ; mode=manual la laisse vide, à vous de la remplir.
curl -X POST /api/v1/admin/imports \ -H "Authorization: Bearer $TOKEN" \ -F "file=@new_titles.csv" -F "mode=manual"2. Corriger la correspondance, par PATCH sur le plan : chaque colonne source pointe vers
un champ du modèle cible.
3. Approuver. Un plan seulement analysé ne s’exécute pas :
409 {"detail":"cannot move import plan from 'analyzed' to 'executed'"}4. Essayer à blanc. C’est l’étape qui justifie tout le reste :
curl -X POST "/api/v1/admin/imports/$PLAN/execute?dry_run=true" \ -H "Authorization: Bearer $TOKEN"{ "dry_run": true, "sources": [{ "target_model": "library_title", "created": 1, "skipped": 0, "errors": [{ "row": 1, "error": "duplicate key value violates unique constraint \"library_title_isbn_key\"\nDETAIL: Key (isbn)=(9780062316097) already exists." }] }]}Ce rapport vient d’un vrai essai : la deuxième ligne du fichier portait un ISBN déjà présent. La table n’a pas bougé d’une ligne. Corrigez le fichier, recommencez : l’erreur est par ligne, avec son numéro, donc on sait laquelle reprendre.
5. Exécuter, la même commande sans dry_run.
Rejouer ne duplique pas
Chaque ligne écrite est enregistrée sous une empreinte de son contenu, dans le registre d’identifiants externes. Relancer le même fichier :
0 created, 1 skippedCe qui vous concerne comme auteur de module
Presque rien, et c’est le but. Trois points seulement :
- Un champ non nullable sans valeur par défaut rendra chaque ligne incomplète refusée. C’est correct, mais dites-le dans votre documentation d’accueil plutôt que de laisser un client le découvrir sur un fichier de 4 000 lignes.
- Une relation se donne par son nom, pas par un identifiant : le noyau résout la valeur
contre le modèle cible et crée l’enregistrement manquant si besoin. Un
genreou une catégorie s’importe donc en clair. - Une contrainte d’unicité est votre amie : c’est elle qui a arrêté l’essai ci-dessus. Un modèle sans unicité accepte les doublons en silence, et personne ne les verra avant le premier rapport faux.