Lacune de correspondance de champs Nostr REST API
Problème
Les clients Nostr qui utilisent à la fois des API REST et des connexions WebSocket pour charger les événements peuvent avoir des fonctionnalités qui fonctionnent de façon incohérente. Les fonctionnalités qui dépendent des valeurs de balises Nostr (comme la balise x pour sha256, ou les balises personnalisées pour les pistes de texte) fonctionnent quand les événements sont chargés via WebSocket (qui fournit l'événement brut complet avec toutes les balises), mais se cassent quand les mêmes événements sont chargés via l'API REST (qui renvoie du JSON aplati/dénormalisé sans le tableau de balises brutes).
Contexte / Conditions de déclenchement
- Une fonctionnalité fonctionne pour certaines vidéos/événements mais pas d'autres (source de données dépendante)
- Un élément UI (comme un bouton CC) s'affiche pour les événements chargés par WebSocket mais pas pour ceux de l'API REST
- Un modèle a des champs nuls qui devraient être remplis (sha256, textTrackRef, etc.)
- La réponse de l'API REST a des champs comme
d_tag,video_url,titlemais PAS de tableautags - La factory
fromJson()analyse les balises pour des valeurs commex(sha256), mais l'API REST n'inclut pas les balises brutes hasSubtitles,hasFeature, ou des getters similaires retournent false pour les données de l'API REST
Cause racine
Les API REST qui indexent les événements Nostr font généralement :
- Extraire les valeurs de balises couramment utilisées dans des colonnes dédiées (d_tag, title, thumbnail, etc.)
- NE PAS retourner le tableau complet de balises brutes dans leur réponse
- Peuvent avoir des champs sémantiquement équivalents sous des noms différents
Par exemple, dans un système vidéo basé sur Blossom :
- La balise Nostr
xcontient le hash de contenu SHA256 - L'API REST retourne
d_tag(qui pour les uploads Blossom EST le SHA256) mais passha256 - La méthode
fromJson()du modèle essaie de trouversha256à partir du champ direct ou de la balisex, ne trouve rien - Les fonctionnalités qui dépendent de
sha256(comme la récupération de sous-titres) se cassent silencieusement
Solution
Étape 1 : Identifier la lacune de correspondance
Comparer ce que l'API REST retourne vs ce que le modèle a besoin :
# Récupérer un exemple de réponse de l'API REST
curl -s "https://your-api.example.com/api/videos?limit=1" | jq '.[0] | keys'
Vérifier quels champs du modèle sont nuls après analyse :
- Regarder la méthode factory
fromJson() - Identifier les champs remplis à partir de l'analyse de balises (tableau tags) qui n'existeront pas dans la réponse REST
- Vérifier si des champs de l'API REST sont sémantiquement équivalents mais portent des noms différents
Étape 2 : Ajouter des correspondances de secours
Dans la méthode fromJson() du modèle, ajouter la logique de secours APRÈS l'analyse primaire :
// Primaire : essayer le champ direct et les balises
var sha256 = eventData['sha256']?.toString() ?? json['sha256']?.toString();
// Analyser à partir des balises si disponible
if (eventData['tags'] is List) {
// ... analyse de balises pour la balise 'x' ...
}
// Normaliser
if (sha256 != null && sha256.isEmpty) sha256 = null;
// SECOURS : Utiliser le champ sémantiquement équivalent de l'API REST
// Pour les uploads Blossom, d_tag EST le hash de contenu (64 caractères hex)
if (sha256 == null && dTag.length == 64 && _isHex(dTag)) {
sha256 = dTag;
}
Étape 3 : Valider que le secours est sûr
S'assurer que le secours ne se déclenche que lorsqu'approprié :
- Vérifier le format/la longueur (SHA256 = 64 caractères hex)
- Ne pas écraser les valeurs explicitement définies
- Gérer les cas limites (importations classiques où d_tag N'EST PAS un hash)
Étape 4 : Ajouter des tests
test('falls back to d_tag as sha256 when d_tag is 64-char hex', () {
final json = {
'd_tag': 'a04b70820ef370e90aae19d23e46b1482d3af0e7c9d994d1594a1384a62d3972',
// No sha256 field, no tags array (REST API response)
...otherFields,
};
final model = Model.fromJson(json);
expect(model.sha256, equals(json['d_tag']));
});
test('does not use d_tag as sha256 when d_tag is not a hex hash', () {
final json = {'d_tag': 'my-video-slug', ...otherFields};
final model = Model.fromJson(json);
expect(model.sha256, isNull);
});
test('does not override explicit sha256 with d_tag', () {
final json = {
'd_tag': 'a04b708...', // 64 hex
'sha256': 'explicit-value',
...otherFields,
};
final model = Model.fromJson(json);
expect(model.sha256, equals('explicit-value'));
});
Vérification
- Charger l'application et naviguer vers un flux qui utilise l'API REST (par ex., tendances/découverte)
- Vérifier que la fonctionnalité fonctionne (par ex., le bouton CC s'affiche ET les sous-titres s'affichent quand activés)
- Vérifier aussi que les événements chargés via WebSocket fonctionnent toujours (par ex., le flux accueil des utilisateurs suivis)
- Vérifier que les d_tags non-hash (importations classiques, slugs personnalisés) ne provoquent pas de faux positifs
Approche de débogage
Quand une fonctionnalité fonctionne de façon incohérente entre les événements :
- Identifier la source de données : L'événement cassé provient-il de l'API REST ou du WebSocket ?
- Comparer les données brutes : Récupérer le même événement des deux sources, diff les champs
- Suivre le pipeline :
Réponse API -> fromJson() -> modèle -> getter -> condition UI - Vérifier les gardes conditionnels : Regarder
if (model.hasX)ouif (field != null)dans l'UI - Enregistrer au niveau du modèle : Ajouter un enregistrement temporaire dans
fromJson()pour voir ce qui est nul
Notes
- Ce pattern s'applique à TOUT client Nostr qui utilise à la fois des sources de données REST et WebSocket
- L'API REST peut évoluer pour inclure plus de champs au fil du temps, donc l'approche de secours est compatible avec l'avenir (les champs explicites ont la priorité sur les secours)
- Envisager de demander à l'équipe de l'API REST d'ajouter directement les champs manquants
- La validation
_isHex()prévient les faux positifs des valeurs d_tag non-hash - Des lacunes similaires peuvent exister pour d'autres champs dérivés de balises (textTrackRef, duration, etc.)
Skills associés
rest-api-optimistic-update-race-condition- Un autre problème de cohérence des données de l'API RESTnostr-addressable-event-d-tag-requirement- Gestion d_tag associée