Aller au contenu

Brancher un autre logiciel sur Kewos

Le reste de ce parcours s’adresse à qui écrit un module. Cette page s’adresse à qui reste dehors : un logiciel tiers, un script de synchronisation, un connecteur maison.

Un jeton, pas un compte

Un autre logiciel n’a pas de compte utilisateur. Il a un jeton de service : pas de user_id, des droits qui viennent uniquement de ses groupes.

from kewos.auth.tokens import create_service_token
issued = create_service_token(engine, name="logiciel-de-la-mairie", groups=("library_reader",))
jeton émis : kws_IfsG4HDR... (36 caractères, la seule copie en clair)
en base : 618039e46002f1cd...
le jeton en clair y est ? False
user_id : None | type : service | groupes : ['library_reader']

La base ne contient qu’une empreinte : elle ne permet pas de rejouer le jeton. Et les groupes suffisent à tout :

GET /api/v1/library_title avec le jeton -> 200
POST /api/v1/library_title avec le même -> 403 (groupe lecteur seulement)
GET /api/v1/library_title sans jeton -> 401

Un intégrateur ne demande donc pas « un compte admin » : il demande un jeton et la liste des groupes dont il a besoin.

Chaque modèle est déjà une API

Il n’y a rien à exposer : tout modèle du registre a son point d’entrée, et les modules du Builder aussi.

GET /api/v1/library_title?genre=science&sort=name&limit=2
{"count": 1, "next_cursor": null,
"results": [{"name": "A Brief History of Time", "genre": "science", ...}]}
  • Tout paramètre qui n’est pas réservé est un filtre de colonne. limit, offset, sort, cursor et tag sont réservés ; genre=science filtre.
  • La pagination se fait par limit/offset ou par curseur (next_cursor), plus sûr quand des lignes s’insèrent pendant que vous paginez.
  • Un champ inconnu est refusé en nommant le champ, pas ignoré en silence : {"field": "order", "reason": "unknown or read-only field"}.

Et l’export sort le même contenu en fichier :

GET /api/v1/library_title/export?format=csv
id,name,author,isbn,published_year,genre,summary,cover,kws_custom_rayon_prefere

Les formats sont csv, jsonl, json, xlsx, xml. Notez la dernière colonne : un champ ajouté à chaud par le client sort aussi, sans que personne ait touché à l’export.

Écrire deux fois sans créer deux fois

Un connecteur qui perd sa connexion ne sait pas si son POST est passé. D’où l’en-tête Idempotency-Key :

POST /api/v1/library_title Idempotency-Key: cmd-4711 -> 201 {"id": 12}
POST /api/v1/library_title Idempotency-Key: cmd-4711 -> 201 {"id": 12}
fiches créées : 1

Le deuxième appel ne rejoue pas l’écriture : il renvoie la première réponse. Réessayer devient sans danger, ce qui est la seule façon d’écrire un connecteur fiable.

Ne pas écraser le travail de quelqu’un d’autre

Chaque fiche porte un numéro de version. En le renvoyant dans If-Match, votre écriture est refusée si la fiche a changé entre-temps :

GET /api/v1/library_title/1 -> version 3
PATCH /api/v1/library_title/1 If-Match: 3 -> 200 (la version passe à 4)
PATCH /api/v1/library_title/1 If-Match: 3 -> 409 "version mismatch -- refetch and retry"

Sans If-Match, la dernière écriture gagne, en silence. C’est un choix à faire consciemment.

La limite de débit

appel 1 -> 200
appel 4 -> 429 retry-after: 36

Le refus est un 429 avec Retry-After en secondes : le client sait quand réessayer au lieu de deviner. Le compteur est par jeton, donc un connecteur bavard ne pénalise pas les autres.

JSON-RPC, pour les actions qui ne sont pas du CRUD

« Confirmer une commande » n’est pas un PATCH. Un module expose alors une méthode :

from kewos.api.jsonrpc import register_jsonrpc_method
register_jsonrpc_method("library.loan.renew", renew_loan)
POST /api/v1/jsonrpc {"jsonrpc":"2.0","method":"kewos.ping","id":1}
-> {"jsonrpc":"2.0","result":{"pong":true,"tenant":"main"},"id":1}
méthode inconnue -> {"error":{"code":-32601,"message":"method not found: 'nobody.home'"}}
mauvaise version -> {"error":{"code":-32600,"message":"invalid JSON-RPC 2.0 envelope"}}
sans jeton -> 401

kewos.ping renvoie le client résolu : un seul appel vérifie que la pile répond et que vous parlez au bon locataire.

Recevoir un appel entrant

L’inverse existe aussi : un prestataire de paiement ou un service tiers vous appelle. Le noyau fournit la vérification de signature et le registre d’idempotence : un même événement rejoué (même fournisseur, même identifiant d’événement) est enregistré une fois et sans effet la seconde fois. La route répond 200 même sur rejeu, parce qu’un prestataire réessaie sur tout code non-2xx et qu’une tempête de 5xx est pire que l’événement perdu.