Sérialisation des données
L'overlay affiche les données de requête en cache sous forme d'arbre JSON extensible. La lisibilité de cet arbre dépend du type T renvoyé par le fetcher : la plupart des modèles ne demandent aucune configuration, et les autres une seule option.
Ordre de résolution de la sérialisation
QoraClient n'a aucune connaissance des types de domaine. Quand un fetch se règle, le résultat est passé au tracker actif selon l'ordre de résolution suivant :
| Priorité | Condition | Résultat |
|---|---|---|
| 1 | QoraOptions.toJson est défini | Appelle la fonction fournie et utilise sa valeur de retour |
| 2 | String, num, bool ou null | Passé tel quel |
| 3 | List | Chaque élément est sérialisé récursivement |
| 4 | Map | Chaque valeur est sérialisée récursivement |
| 5 | Objet avec une méthode toJson() | Appelée via dispatch dynamique, résultat utilisé |
| 6 | Tout le reste | .toString() appelé, affiché comme chaîne simple |
Le parcours est récursif. Un List<Map<String, User>> est géré correctement sans configuration, à condition que User implémente toJson().
Scénarios courants
json_serializable et freezed
Les deux générateurs de code produisent une méthode toJson(). Le sérialiseur la détecte et l'appelle automatiquement. Aucune configuration supplémentaire n'est requise.
// @JsonSerializable() ou @freezed : pas de config supplémentaire nécessaire
fetchQuery<User>(
key: ['users', userId],
fetcher: () => api.getUser(userId),
);
L'overlay rend le graphe d'objets complet sous forme d'arbre extensible.
Réponses Map brutes
Quand le fetcher retourne Map<String, dynamic> directement (par exemple, après décodage manuel du corps de la réponse HTTP), aucune configuration n'est requise.
fetchQuery<Map<String, dynamic>>(
key: ['users', userId],
fetcher: () async {
final response = await http.get(Uri.parse('/users/$userId'));
return jsonDecode(response.body) as Map<String, dynamic>;
},
);
Cette approche ne nécessite aucune configuration de sérialisation. L'étape de désérialisation doit être gérée dans le fetcher ou la couche repository plutôt que dans un widget consommateur.
Modèles manuels sans toJson
Quand un modèle n'a pas de méthode toJson(), le sérialiseur revient à .toString() et affiche un nœud de chaîne unique. Pour produire une sortie structurée, fournir un sérialiseur explicite via QoraOptions.toJson.
fetchQuery<User>(
key: ['users', userId],
fetcher: () => api.getUser(userId),
options: QoraOptions(
toJson: (data) => (data as User).toJson(),
),
);
Listes
Les listes d'objets typés suivent les mêmes règles de résolution. Quand le type d'élément implémente toJson(), chaque élément est sérialisé automatiquement.
fetchQuery<List<Post>>(
key: ['posts'],
fetcher: () => api.getPosts(),
// Post implémente toJson() : détecté automatiquement, pas de config supplémentaire.
);
Quand les éléments individuels n'ont pas de toJson(), fournir un sérialiseur :
fetchQuery<List<Post>>(
key: ['posts'],
fetcher: () => api.getPosts(),
options: QoraOptions(
toJson: (data) => (data as List<Post>).map((p) => p.toJson()).toList(),
),
);
L'option toJson
QoraOptions.toJson accepte toute fonction avec la signature :
Object? Function(Object? data)
La valeur de retour doit être JSON-safe : Map<String, dynamic>, List, String, num, bool ou null. Retourner tout autre type causera une erreur d'exécution quand le rendu DevTools encode la valeur.
// Le cast est sûr : T est User et data est le résultat du fetcher.
options: QoraOptions(
toJson: (data) => (data as User).toJson(),
),
toJson suit les mêmes sémantiques de fusion que tous les autres champs de QoraOptions. Une valeur sur QoraClientConfig.defaultOptions s'applique globalement et peut être remplacée par requête.
Quand utiliser chaque approche
| Situation | Recommandation |
|---|---|
Modèles json_serializable ou freezed | Pas de configuration requise. Détecté auto. |
Map ou List bruts depuis jsonDecode | Pas de configuration requise. Passé tel quel. |
Modèle manuel avec une méthode toJson() | Pas de configuration requise. Détecté auto. |
Modèle sans toJson() | Fournir QoraOptions(toJson: ...). |
Sérialisation personnalisée avec une signature toJson non standard | Fournir QoraOptions(toJson: ...). |
Impact en production
Le chemin de sérialisation (_serializeForTracker) n'est exécuté que quand QoraTracker.needsSerialization retourne true. En production, QoraClient utilise par défaut NoOpTracker, qui retourne false. Aucune sérialisation ne s'exécute et aucun overhead n'est introduit.
final client = QoraClient(
tracker: kDebugMode ? tracker : null, // null active NoOpTracker
);
Overlay intégré
Un panneau de débogage flottant rendu à l'intérieur de l'app Flutter. Inspectez les requêtes, mutations et mises à jour optimistes sans outil externe.
Avec Provider
Ajouter Qora à une app Provider existante pour spécialiser la gestion de l'état serveur tout en conservant Provider pour l'état UI et l'injection de dépendances.