Documentation J+SERVICES Guides Référence API

Contrat API — Interpréter nos réponses (app mobile)

Le principe en une phrase : une requête qui n’aboutit pas côté app n’est pas une opération qui a échoué côté serveur. Avant d’afficher « échec », relisez l’état.

Ce guide s’adresse au développeur de l’application mobile. Il corrige des faux échecs observés en production le 2026-08-16 sur MikhmonPro/4.5.1.


1. Le cas qui a motivé ce guide

Un enrôlement RADIUS a été signalé « échec » à l’utilisateur. Voici ce qui s’est réellement passé, à la seconde près :

18:59:10   POST /api/v1/radius/nas          requête reçue par le backend
18:59:10   FreeRADIUS redémarre             le NAS est écrit, le service recharge sa conf
18:59:18   FreeRADIUS est reparti           8 secondes plus tard
           journal HTTP : statut « - »      l'app avait déjà fermé la connexion

L’opération a réussi. Le NAS était bien enregistré, actif, rattaché au bon routeur. L’utilisateur, lui, a vu un échec — et a recommencé, déclenchant un nouveau redémarrage.

Un statut vide dans nos journaux ne signifie pas « erreur » : il signifie que personne n’attendait plus la réponse.

Ce n’est pas un cas isolé

Sur les 14 890 requêtes émises par l’application le 2026-08-16 :

Réponse Volume Lecture
304 6 856 données inchangées — pas une erreur
200 5 996 succès
abandonnée 1 112 l’app a raccroché avant la réponse
403 617 droit absent — inutile de réessayer
401 161 jeton à rafraîchir
409 21 conflit — souvent déjà fait
429 11 quota atteint
500 5 vraie erreur serveur

1 112 requêtes abandonnées, soit une sur treize. Chacune peut correspondre à une opération qui a abouti côté serveur pendant que l’écran affichait un échec.


2. Les délais d’attente à prévoir

Toutes les écritures ne se valent pas. Certaines déclenchent un travail d’infrastructure :

Appel Attendre au moins Pourquoi
POST /api/v1/radius/nas 30 s écrit le NAS puis recharge FreeRADIUS
POST /api/v1/clients/vpn/provision 30 s pose le pair WireGuard et publie les ports
Lectures (GET) 10 s agrégations côté serveur

Un délai plus court ne protège pas l’utilisateur : il lui cache seulement le résultat.


3. La règle d’or : relire avant de déclarer un échec

Sur timeout ou connexion coupée, ne concluez jamais à l’échec. Relisez l’état :

POST /api/v1/radius/nas   →  timeout
        ↓
GET /api/v1/radius/nas    →  le NAS y est ?  →  SUCCÈS (afficher « déjà configuré »)
                          →  absent ?        →  proposer de réessayer

Le même raisonnement vaut pour le provisioning VPN et la création de profils. Une écriture sans réponse est un état inconnu, pas un état échoué.


4. Les réponses à ne pas traiter comme des erreurs

409 — conflit, souvent « c’est déjà fait »

L’enrôlement d’un NAS est idempotent : si le routeur est déjà rattaché à la même allocation, le backend renvoie l’enregistrement existant avec idempotent: true dans le corps. C’est un succès, à présenter comme « déjà configuré ».

Un vrai conflit porte un code explicite dans le corps :

code Sens Action utilisateur
RADIUS_NASNAME_CONFLICT l’adresse de tunnel est prise par un autre NAS contacter le support
RADIUS_ALLOCATION_CONFLICT l’allocation est rattachée à un NAS incohérent contacter le support
VPN_TUNNEL_NOT_CONNECTED le tunnel doit être monté d’abord reconnecter, puis réessayer
VPN_ALLOCATION_INACTIVE le VPN n’est pas actif vérifier l’abonnement
ROUTER_SERIAL_MISMATCH le routeur n’est pas celui verrouillé vérifier l’équipement

Affichez le message du corps, pas « erreur 409 ». Chacun de ces cas appelle une action différente de l’utilisateur.

202 — accepté, pas terminé

POST /api/v1/clients/remote-access/provisioning-events répond 202. L’événement est pris en compte, le traitement continue en arrière-plan. Ce n’est ni un succès final ni un échec : n’affichez pas de résultat, laissez l’écran en cours.

304 — rien n’a changé

46 % de votre trafic. Réutilisez les données en cache : ne videz pas l’écran, ne montrez pas d’erreur, ne relancez pas la requête.

403 — le droit manque, pas la connexion

617 réponses 403 aujourd’hui, surtout sur /radius/analytics, /radius/sessions et /radius/vouchers. Un 403 ne se répare pas en réessayant : la licence ou l’entitlement n’autorise pas cet appel. Cessez d’interroger l’endpoint pour cette session et affichez l’écran « fonctionnalité non incluse ».

Réessayer en boucle consomme le quota partagé et fait échouer d’autres appels légitimes.


5. Quota — 100 requêtes / 15 min par IP, partagées par TOUTES les routes /api

11 réponses 429 aujourd’hui. Le piège est connu : une vue qui sonde en boucle consomme le quota, et ce sont les autres appels — licence, VPN, paiement — qui échouent. La route fautive, elle, semble fonctionner.

À corriger en priorité, d’après le trafic observé :

Règles : interroger à l’ouverture de l’écran, rafraîchir sur action explicite, une seule sonde à la fois (annuler la précédente), et respecter les en-têtes de cache — le 304 prouve qu’ils fonctionnent déjà.


6. Ce qu’il faut afficher à l’utilisateur

Situation À afficher
timeout, puis relecture confirmant l’état « Configuration terminée »
timeout, puis relecture ne confirmant rien « Vérification impossible, réessayez »
409 avec idempotent: true « Déjà configuré »
409 métier le message du corps, tel quel
403 « Fonctionnalité non incluse dans votre licence »
401 rafraîchir le jeton, sans message d’erreur
429 « Trop de requêtes, patientez » — et arrêter les sondes
500 « Erreur serveur » — le seul cas où le mot « erreur » est juste

Ne montrez jamais un code HTTP brut. Et surtout : ne dites pas « échec » quand vous ne savez pas. Un utilisateur qui croit avoir échoué recommence, et chaque reprise d’un enrôlement RADIUS redémarre FreeRADIUS pour tout le parc.


7. Voir aussi