Questions GraphQL et la RFC pour l'APi GVA

Salut @Inso, @vtexier et @kimamila :slight_smile: Vous allez bien ?

J’ai besoin de votre aide pour comprendre la RFC GVA que vous avez co-rédigés, Benoit je te met aussi dans la boucle car j’ai des questions sur GraphQL :sweat_smile:

Voila j’ai un étudiant en informatique qui voudrais contribuer à Durs (Duniter-Rust), il s’avère qu’il doit réaliser un petit projet perso de 30 jours pour son école et il se propose de plancher sur l’api GVA.

Pour pouvoir l’accompagner j’ai besoin de comprendre un peu mieux GraphQL et la RFC GVA, voici mes questions :

  1. Peut on avoir plusieurs schemas dans une meme API GraphQL ? J’ai lu sur le site officiel de graphql que le principe ,c’est d’avoir un endpoint unique, du coup ça implique 1 seul schéma pour toute l’API ?

  2. Apparemment un peut déclarer une seule requête racine par Schéma, cette requête racine peut t’elle contenir des sous requêtes ?

  3. Dans le schema de la RFC comment est fait le lien entre une Sandbox et une Identity ? Il ne manque pas quelque chose ? Le type Identity doit bien être inséré quelque part pour être requêté non ? Sinon, pouvez vous me donner un exemple de rêquete permettant d’obtenir une Identité a partir de ce schéma ?

Dsl si je pose des questions de noob, mais je ne connaissais rien a GraphQL il y a encore quelques heures, je viens de passer 3 heures a lire de la doc sur GraphQL mais la j’ai besoin d’échanger avec des connaisseurs pour comprendre :grin:


J’ai aussi des questions sur les choix de conception dans la RFC, donc pas liés a ma méconnaissance de GraphQL.

J’ai l’impression que la RFC ne traite que le cas des documents en piscine, quid des documents en blockchain ?
Il faudrait une façon a part pour requeter les documents en blockchain car ça demande générament moins de paramètres (1 seul au lieu de 3 dans le cas d’une identité).
Ou alors si on préfère une façon unique d’accéder au document il faudrait rajouter un champ (un booléen) qui indique si le document proviens de la sandbox ou de la blockchain non ?

Merci pour vos éclaircissements :grinning:

J’ai initié la RFC avec @inso, et on a dégrossit quelque points, mais les exemples ne sont pas à prendre au pied de la lettre.

La seule chose un peu concrète a été le début de schéma donné en fin de RFC pour que @cgeek puisse commencer à jouer avec, mais il est très rudimentaire. @cgeek a expérimenté un début de module nodejs je crois, et @kimamila s’est penché sur la partie cliente.

Bref, je pense que les deux personnes les plus expérimentées sur le sujet sont @cgeek et @kimamila.

La RFC est à considérer comme un wiki ou chacun peut ajouter ses découvertes, conseils, bonnes pratiques, etc pour aboutir à un document de départ facilitant la description de l’API GVA.

Pour répondre à tes questions :

  1. GraphQL est une API de type RPC, donc avec un seul endpoint d’accès, le contenu des requêtes/réponses ne dépendent pas de l’url et cela permet de pouvoir faire des connexions avec d’autres protocoles que http (websocket par exemple pour les subcriptions, qui permettent au serveur de faire du push sur une connexion permanente) .

  2. Joker :flushed:

  3. Il n’y a pas de lien entre les deux. J’ai mis un exemple de requête de l’espace consommé dans les sandboxes inspiré de BMA, et un exemple d’envoi d’identité vers le serveur, mais les deux n’ont pas de liens. Il manque la requête d’une identité, effectivement, le schéma est une ébauche, rien de plus.

    #################################
    # NODE queries
    #################################

    type Query {
      node: Node
      identity(
        uniqueID: String!
        timestamp: String
      ): Identity
    }

Dans cet exemple, j’ajoute la requête “identity(uniqueID, timestamp)” avec le paramètre “timestamp” optionnel. En retour, un objet json de type Identity est retourné.

La requête côté client :

query {
       identity (uniqueID: "toto") {
         uniqueID,
         timestamp,
         currency,
         issuer
      }
     }

Le retour en json :

    {
      "data": {
        "Identity": {
                 "uniqueID": "toto",
                 "timestamp: "XXX-000XXXXXXXXX",
                 "currency": "g1",
                 "issuer": "f45d844d4f8s4fs4df84xdf4xd84xd4fx8d4f"
        }
      }
    }

Bon c’est fait à la main donc je peux me planter. :wink:

Si tu aimes Star Wars : https://swapi.graph.cool/

1 J'aime

Ok entre temps j’ai eu d’autres infos sur GraphQL et je comprend mieux le fonctionnement, merci beaucoup :slight_smile:

Du coup je vous propose un complément pour se 1er schéma portant juste sur les identités, j’ai ajouté un champ booléan “written” indiquant si le document a été écrit en blockchain ou non, ça permet 1. de savoir l’état du documente t 2; de requeter spécifiquement que les certif en blockchain ou que celles en sandbox :slight_smile:

Aussi j’ai proposé une requête sans paramètre obligatoire car selon les cas il n’existe aucun paramètre que l’on utilisera toujours a coup sur, voici donc la nouvelle query root que je propose :

type Query {
    node: Node
    getIdentities(
        issuer: String
        uniqueID: String
        timestamp: String
        written: Boolean
    ): [Identity!]
}

Je l’ai ajoutée a la RFC mais c’est une proposition a valider ou pas (la rfc n’est pas encore mergée de toute façon). J’aimerais qu’on en discute car je vais devoir donner un schéma a l’élève qui vas commencer GVA pour Durs donc autant lui donner un schéma qui se rapproche de ce qu’on fera en vrai :slight_smile:

Concernant l’identité je propose de renommer UniqueID par username c’est plus parlant. d’ailleurs UniqueID est trompeur car en sandbox plusieurs identités peuvent avoir le même UniqueID, ce qui est antinomique.

Alors certes on ne peut pas modifier les nom des champs du format raw, mais dans le schéma grapql on met le nom de champ que l’on veut 'après c’est les résolvers qui font le lien) donc autant choisir des noms plus parlant :slight_smile:

1 J'aime

Je préfèrerais UsernameID car c’est bien un identifiant en block chain, mais avant d’être inscrit ce n’est qu’un username parmis d’autres.

1 J'aime

Salut !

Pas sur de comprendre ta question…

Qu’une manière générale, je penses qu’il faut qu’on fixe une nomenclature.
dans BMA, plusieurs champs ont évolué avec le temps : uid/UniqueID, pub/pubkey, sec/seckey, buid/block/blockstamp/timestamp

Bref, je serai pour que la RFC commence par figer ces termes, puis les utilise de la même manière dans le schema graphQL.

…enfin si c’est possible.

Oui, j’ai un Cesium 2 (en Ionic 4, Angular 6) qui fait des les premières requêtes GraphQL :slight_smile:

J’ai vraiment hate de réécrire Cesium… mais je penses débuter par un seul écran, très light et synthétique, pour les paiements/réceptions très rapide. L’idée est d’avoir une bonne gestion de compte, mais pas forcément les boutons certifications etc.

3 J'aimes

Si vous voulez je peut faire une proposition de termes pour tout les champs de tout les documents, puis on discute a partir de cette base, ça vous irai ? Je peut faire ça WE prochain :slight_smile:

2 J'aimes

@cgeek @Junidev sur le principe, que pensez vous de l’idée d’essayer de trouver un schéma GraphQL commun aux 3 implémentations du protocole DUP ?

L’avantage serait que les développeurs de programme tierces souhaitant interroger les données de la blockhain auraient un seul schéma a étudier sans avoir a se soucier des spécificités de chaque implémentation :blush:

De plus, grâce a GraphQL chaque implémentation pourra sans probleme exposer une extension spécifique de son schéma sans que cela n’impacte les applications tierces qui se bases sur le schéma commun.

Par exemple le schéma GraphQL de Durs exposera probablement des requêtes en plus qui serviront a g1-monit-v2 ou tout autre projet/envie que j’aurais d’ici la, et grâce a GraphQL cela n’impactera pas les clients et applications tierces utilisant la partie commune du schéma :wink:

Si vous êtes ok sur le principe, alors je vous soumettrais prochainement une proposition de schéma commun complet incluant tout les documents, ça nous fera une base pour échanger :slight_smile:

EDIT : Ce sera qu’une proposition hein, si vos retours impliquent de la modifiée entièrement y a pas de soucis ^^

moi la seul question que j’ai c’est est-ce qu’on utilise les souscription de graphql pour l’échange de documents, si oui, qui à essayé? est-ce que c’est fiable ? comment on l’adapte ?

Le mot souscription suggère que la synchro est unidirectionnel, il faut deux canal pour une synchro bidirectionnel.
pourquoi ne pas imaginer un protocole à partir de liens unidirectionnels ? une liste de vecteurs et hop le tour est joué ? “you cant always pay it back, but you can pay it forward”

oui pour ce qui est des champs de bases c’est a dire une api Minimal incluant tout les champs nécessaires.

après tu peux publier la tienne comme cgeek a fait et dont j’ai pomper le schéma
https://juniter.bnimajneb.online:8443/graphiql (la plupart des requêtes sont pas mappé, ne vous acharnez pas )

en fait y’a déjà une base pour discuter, perso je suis pas entièrement satisfait de l’état dans lequel sont les Transactions du schéma, par exemple, on pourrais faire plus de structures imbriqué… Je penses que tu devrais faire ton service g1-monit et l’exposer, ça permet d’inspirer les autres et peut être même d’obtenir un consensus par consentement par initiative, un peu comme le calcul d’un bloc ou le développement de Duniter jusque là.
Je vois les services BMA changer à chaque version alors je me dis que si GVA se créer naturellement en fonction des besoins c’est peut être une bonne chose.

1 J'aime

Perso je compte commencer simple (sans souscription) dans un 1er temps pour Durs, donc je n’ai pas essayé. Je crois que l’idée de la RFC initiée par @Inso et @vtexier c’était de proposer les deux : un endpoint sans souscription et un 2ème endpoint avec souscriptions qui serait par convention égal au 1er avec le path /subscriptions a la fin.

Dsl si je pose une question de noob mais tu parle de quoi par “synchro” ?
Si tu parle de la synchro de la blockchain, dans Duniter et Durs ça ce fera pas via GVA qui est destinée exclusivement aux clients et app tierces mais via WS2P. Du coup je suppose que tu parle d’autre chose ?

Pour répondre a quel besoin ?

Cool on est d’accord sur ce point, reste plus que l’avis de @cgeek :slight_smile:

Je n’en ai pas encore, je voulais justement savoir ce qui avait déjà été fait avant de commencer :slight_smile:

Quelle base ? Pour moi la référence c’est la RFC? or sur la RFC y a presque rien, un schéma quasi-vide.

Si tu veut on peut parti du schéma que tu expose, j’ai de nombreux retours a faire sur les nom du coup, mais je ferai ça demain soir il est tard :slight_smile:

Oui c’est une bonne idée, faudrait qu’on creuse ça :slight_smile:

En fait ce sera pas un service mais un client qui utilisera mon API, c’était juste un exemple pour rassurer sur le fait qu’on est pas obligé d’avoir le même schéma, l’idée c’est juste d’avoir une base de commune pour le minimal.

Tout a fait et c’est très chiant pour les dev des clients et app tierces, @kimamila exprime le besoin qu’on fasse un schéma stable qui ne bougera pas (ou très lentement), du coup ça peut être pas mal d’essayer de nous mettre d’accord sur les besoins et les objectifs de cette API.

En tout les cas la base existante me semble très très incomplète du coup ce week-end je vais plancher sur un schéma complet et détaillé qui visera a répondre a tout les besoins minimaux (fournir le nécessaire aux clients naïfs et clients multi-nœuds).

Dans son état actuel, la RFC doit effectivement être enrichie par les exemples fonctionnels qui ont été codés.
En aucun cas elle ne saurait être la bible/documentation à suivre pour l’instant, car c’est une ébauche, mais elle a pour but de le devenir.

Donc tu peux la modifier pour en faire une spécification que les clients suivront. Yapluka ! :wink:

Le deuxième point d’accès obligatoire pour les souscriptions est une limitation repérée par @cgeek, donc si on veut du push serveur -> client via websocket, il faut une seconde url de endpoint.

https://swapi.graph.cool/ est une mine d’informations, en examinant le schéma contenant des requêtes filtrées et paginées !

1 J'aime

Voila je viens de rédiger une proposition de schéma complet et générique qui me semble répondre a la plupart des besoins, il manque encore :

  • Les requêtes de type réseau (obtenir les peer et heads) -> c’est pas grand chose a faire mais j’ai besoin de passer a autre chose, je rajouterai ça au plus tard WE prochain si personne ne le fait d’ici la
  • La partie arbre de Merkel car je n’ai pas encore cerné les besoins avec précision, j’ai quelques questions a ce sujet (voir plus bas)
  • D’autres chose que j’aurais oublié ?

Comme vous l’aurez compris j’ai besoin de spécifier avant de faire, dans l’idéal j’aimerais ne commencer a coder que lorsque nous seront en grande partie d’accord sur le schéma a implémenter (dans les faits mon étudiant vas de toute façon de voir commencer quitte a se qu’on révise après).

N’hésitez pas a me poser des questions pour éclaircir certains points du schéma, j’ai écrit quelques commentaires mais pas partout, a terme il faudra commenter tout les champs je pense :slight_smile:

Quelques précisions :

  • La nullité ou non de chaque champ a été mesurée et a un sens précis qui peut être différent selon le contexte : dans certain cas la nullité signifie que ce champ n’e"st pas fourni par toutes les implémentations. Exemple : Durs donnera beaucoup d’infos sur la distance, la seule info obligatoire étant un booléan pour savoir si la distance est ok, les autres champs sont nullables, il vous suffit donc d’implémenter un résolver qui retourne toujours null :wink:
  • La pagination est obligatoire et est gérée de façon identique pour toutes les requêtes via l’objet Paging.
  • les noms des champs pour les documents sont uniformisés (par exemple tout les documents sauf la revoc ont un blockstamp, donc il s’appelle blockstamp). Je ne souhaite pas reprendre les nom du format raw qui sont beaucoup moins parlant dans certains cas. Rapellons que la plupart des dev dans un premier temps ils feront des queries pas des mutations, poster des documents c’est un pallier au dessus (et y a déjà des outils a part pour aider a ça comme dup-tools).

Questions concernant la partie arbre de merkel :

Je distingue deux besoins : d’une part vérifier la véracité et d’autre part détecter les changements d’états, j’ai bon ?

Si je comprend bien l’idée c’est de demander les données a un seul nœud et de demander une empreinte aux autres nœuds pour vérifier si elle correspond a l’empreinte calculée depuis les données ?
Pour les documents il suffit de demander comme empreinte le seul champ signature. Du coup les seuls cas un je trouve l’arbre de merkel pertinent c’est pour :

  • la liste des sources
  • les champs memberships et certifications de l’identité.

Mais plutôt que de hasher tout les champs on peut faire plus performant : un seul hash par document. De toute façon les document sont immuables donc c’est équivalent. La seule exception étant le champ written on peut donc dire :

HASH_FIELD = hash(HASH_DOCUMENT + written)

Mine de rien on calcule 3 hashs par document au lieu de 11 pour les memberships et même 12 pour les certs. Soit environ 75% d’économies de calcul :slight_smile:

current: Block
block(number: Int!): Block

pourquoi ne pas garder …

block(number: Int): Block

La version actuellement spécifié par l’api gva de duniter semble tirer partie de la nullabilité de l’attribut. pourquoi changer et dupliquer la méthode?

type Mutation {
addIdentities (
rawDocuments: [String!]!
): [Identity!]

Pourquoi des ajouts groupé ?

Je pensais plutôt a une fonction unique ici

submitDoc(rawDocument: String!): boolean !

parce que la valeur de retour est inutile. je m’en fou de savoir comment le nœud que j’ai contacté valide le document, ce qui m’intéresse c’est de savoir si le reste du réseau va le faire. j’ai donc ni besoin d’array ni besoin de 4 fonctions. et si je m’intéresse à l’état du documents il m’est plus utile d’aller vérifier un autre nœud. un booléen me semble suffit mais je peut oublier un truc.

dans le block

identities: [Identity!]!
joiners: [Membership!]!
actives: [Membership!]!
leavers: [Membership!]!
revoked: [CompactRevocation!]!
excluded: [String!]!
certifications: [CompactCertification!]!
transactions: [Transaction!]!

CompactRevocation & CompactCertification ?

input BlockstampInput {
type Blockstamp {

Pourquoi 2 type ?? ne peut t’on pas réutiliser le type Blockstamp ?

blockstamp: Blockstamp

Blockstamp comme nom de type, ok, mais n’y aurait-il pas quelque chose de plus explicite comme nom de variable. des bstamp j’en ai partout dans le code, si je les nomme pas je sais pas ce que c’est !

type Certification {
type: String!
currency: String!

C’est un choix particulier de vouloir la currency a chaque requête, c’est bien pour des systeme multi chain mais ça implique que les requêtes et / ou réponse devront contenir le champ. Je suis plutôt favorable à 1 seul entry point / monnaie. rien ne t’empêche de faire un deuxième entry point dans ton noeuds.

Distance,

Créer un objet pour répondre as ton besoin sur la distance, s’il te plaît fait le dans un autre modèle, il me sembles un peu inutile de wrapper un booleen non ? Ptet que toi ca t’arranges pour le coup mais perso je trouves qu’il vaut mieux faire un autre attribut optionnel pour le detail que de wrapper la variable minimal.
Par contre j’attends de pouvoir requêter ces valeurs sur ton noeud.

Membership

mb: Membership

Pending memberships

pMbs: [Membership!]!

Received certifications

recvCerts: [Certification!]!

faut renommer ça! autant être verbeux jusqu’au bout ! moi je rajouterais même les transactions ici en optionnel.
Parce que d’un point de vue client, c’est super facile et intuitif .

written: Boolean

WTF ! c’est incomplet ou alors particulièrement spécifique à ton modèle, t’en met partout ,
sous forme de boolean, je doutes que ce champs permette d’être consistant. comme variable input éventuellement, mais je l’appellerais pending dans ce cas, plus spécifique. mais alors certainement pas dans le champ de retour, c’est incomplet, il faut le bstamp written_on.

le Type Node est inutile, car les requêtes en graphql peuvent être groupé …

paging: Paging!

j’aime bien, je vais tester, mais je garderais quand même la fonction de base count / from, aucune raison de faire chier les devs qui ont pas besoin de pagination et puis la il faut éventuellement rendre paging optionnel pour pouvoir tout charger.

De quel arbre de merkel tu parles au juste? Ya pas besoin d’arbre de Merkle si le réseau fonctionne en push… Pour répondre à quel besoin?

Conclusion

Il ne s’agit pas d’un algorithme complexe. qu’il faut expliquer, il s’agit d’un schéma de donnée avec ses contraintes. La ‘spécification’ qui précède l’expérience et l’analyse est souvent incomplète et non fonctionnelle.
Il n’y a rien qui nécessite une spec, il y a juste besoin d’une bonne doc un fois construite.

l’expérience me semble être une bien meilleur référence qu’un brouillon.

D’ailleurs, si tu élargis ta définition du mot à celle du dictionnaire, tu t’apercevra que référence, dans le domaine de la documentation, requiert un existant, il m’est tout particulièrement étrange que tu l’emploi avec pour objet le commentaire d’un inexistant. :wink:

Parce que j’ai envie que le schéma soit évocateur de lui même, avec ta version on devine pas directement comment avoir le bloc courant, ce qui est une requete de base que tout débutant voudra réussir a faire rapidement.
La version précédemment spécifiée n’incluais pas la requête block. Il s’agit uniquement du schéma que tu a choisi d’exposer sans qu’il ne soit consigné dans aucune RFC, je veut bien croire qu’il s’agit d’une reprise du schéma de cgeek mais idem je n’en ai jamais eu connaissance avant que tu partage le lien de ton schéma.
De toute façon j’ai déjà tenu compte du schéma que tu expose et j’en ai gardé ce qu’il me semblait pertinent de garder, donc pas grand chose en effet :slight_smile:

D’une manière générale il me semble que :

  • Le schéma doit être évocateur de lui même, donc fortement typé et avec des requêtes au nom évocateur.
  • La nullité doit être prohibé autant que possible, car source d’effets de bords

Ben non la encore pour des raisons de simplicité d’accès aux autres dev, on n’est bien content d’avoir le retour jsonifié de notre document pour nous assurer qu’il a bien été parsé comme il faut. Si j’ai juste un “true” je reste sur ma faim, je sais que le document a été validé certes (si ce n’est pas un bug qui renvoie ce true) mais je ne sais pas ce qu’a donné le format final de mon document.
Pour moi la seule et unique raison de passer par une API textuelle c’est de simplifier l’expérience des dev extérieur, donc quitte a perdre en perf pour une API textuelle autant aller au bout de la démarche, sinon je fais une API binaire et puis voila.

Le block ne stocke pas tout les champs de ces 2 documents mais seulement une partie des champs, je ne peut donc pas retourner le Document d’origine (sauf a rendre nullable les champs non fourni mais je suis contre les champ nullables) du coup j’appelle ça la version “compacte” du document :slight_smile:

Peut être que si, c’est un type qui doit pouvoir être passé en input et en output, je ne connais pas assez bien GraphQL pour savoir comment le déclarer en une seule fois (ni si c’est possible).

blockNumberAndHash ?

Je ne veut pas la currency a chaque requête, je dit juste que si la currency est demandée alors le champ retourné ne peut pas valoir null. Dans les faits le client ne demandera que rarement ce champ :slight_smile:

Ok je vais regrouper les champ facultatifs dans un seul champ detailledDistance que je n’ajouterai nqu’a mon schéma :slight_smile:

En fait je propose ça car le code Rust calculant ces valeurs existe déjà, on l’avais écrit avec nano pour pouvoir étudier plus finement la wot, du coup je me dit autant les exposer dans la future API GVA que mon élève vas commencer a dev.

Ok je vais renommer ça, tu a raison autant être verbeux jusqu’au bout :slight_smile:
Tu veut dire les transactions émises par l’identité ?
Je trouve plus clair de séparer clairement la partie wot de la partie monnaie, je pense que mélanger les deux est une mauvaise idée :confused:

Ok je peut le renommer pending :slight_smile:
Par contre written_on ne sera pas dans le schéma commun car je ne fourni pas cet info.(ou alors en nullable avec précision en commentaire que le champ n’est pas fourni par toutes les implémentations).

Peut tu m’en dire plus ? Comment doit-je exposer les champ du type Node du coup ?

L’idéal serait que le schéma GraphQL puisse intégrer une valeur par défaut pour l’input Paging mais je ne sais pas si c’est possible ? @vtexier @Inso une idée ?
En tout les cas je ne souhaite pas offrir aux clients la possibilité de tout charger, c’est la porte ouvertes aux attaques par spam de requêtes lourdes. Donc si on rend le paramètre nullable faut bien préciser en commentaire qu’on aura quand même une pagination avec les valeurs par défaut.

Lis la RFC c’est marqué dedans :slight_smile:

Ni l’un ni l’autre, il s’agit d’un schéma de requêtes et non pas de données :wink: Il en représente pas les données réelles mais les façons de les optenir.

C’est la notre plus grand désaccord. L’analyse c’est ce qu’on est en train de faire, ce que j’ai en tout cas fait avant de proposer ce schéma. Quand a l’implémentation en elle même, perso je n’ai pas besoin d’api GVA et si j’en code une se sera uniquement pour répondre a un, besoin extérieur: celui des dev des clients, donc c’est eux que j’écouterai et je ne perdrais pas une seconde a coder dans le vent tant que je n’aurais pas leur accord sur le schéma que je doit implémenter pour eux.

Au contraire la spécification est essentielle ,et doit être pensée en amont, évidemment que face a l’expérience il faut réadapter les spec petit a petit mais ce n’est pas censé changer du tout au tout :wink:

Un peu de sérieux, faire d’abord et penser après ça marche pour un projet perso dans son coin, c’est- pas envisageable pour un projet complexe et critique en équipe. Tout les grands projets sérieux fonctionnent avec des RFC, de plus la mise en place du fonctionnement par RFC a été demandé par de nombreux dev de la communauté dont @Inso @vtexier et @nanocryk.

Si tu veut qu’on travaille ensemble il faut respecter le fait qu’on passe par des RFC pour spécifier, les constituent “l’espace officiel” pour faire une proposition d’évolution. L’api GVA est une proposition d’évolution, lorsqu’elle sera complète on la développera puis on réadaptera les spec au fur et a mesure de l’expérience puis on mergera la RFC quand le dev de GVA v1 sera terminé.

Évidemment qu’on ne peut pas pondre des spec parfaites dés le départ et que l’expérience nous montre des choses qu’on a oublier ou mal conçues, c’est le chemin que j’avaie suivi pour WS2Pv2 dont la RFC n’est toujours pas mergée alors que les spec sont écrites depuis 6 mois, je mergerais quand j’aurais fini le dev.

@Inso @vtexier @kimamila @Moul c’est uniquement pour vous les dev des clients qu’on vas implémenter l’API GVA, donc c’est a vous de nous remonter vos besoins.
J’ai fait une proposition de schéma GraphQL en annexe de la RFC, pouvez vous me faire un retour ?

Je vais répondre directement sur le git pour les questions/remarques concernant directement l’API.

Par rapport à vos échanges, je me réjouis de voir les développeurs des noeuds tenter de s’accorder ensemble avant de développer : ça nous aidera beaucoup côté client. A ce sujet, je suis plutôt d’accord avec @elois sur :

  • Le paging doit être obligatoire. On ne peut pas imaginer une blockchain tourner sur plusieurs dizaines d’années sans avoir des requêtes paginées forcées sur les clients. Il faut d’ailleurs définir une taille de page maximum

Je suis plutôt d’accord avec @junidev sur :

  • written_on : ce champs doit être présent pour permettre l’exploration de la blockchain par les clients :
    • Pour les utilisateurs : clic-droit -> atteindre le bloc contenant le document
    • Pour les développeurs : Techniquement ce champs est nécessaire pour les résolutions de fork (si une donnée est en cache et que la chaine a forkée, si on ne connait pas le bloc de l’élément, on ne peut pas savoir si il faut nettoyer le cache)

Je suis en désaccord avec vous deux sur :

  • Le schéma GraphQL doit être commun à tous les noeuds. Sinon, ça va être l’enfer à gérer côté client. Les clients doivent déja se méfier du réseau et vérifier toutes leurs requêtes, si en plus ils doivent prévoir des requêtes différentes en fonction du type de noeud en face, ça va être infernal.
  • Pour permettre aux noeuds de faire des requêtes spécifiques (par exemple pour g1-monit), il faudra imaginer un système d’extension de requêtes à GraphQL. Par exemple, une extension pour les requêtes nécessaires à g1-monit v2.
  • Il faudra mettre en oeuvre un versionning pour que les noeuds n’aient pas à s’attendre pour faire évoluer l’API.
  • Donc en gros, je propose de prévoir un schéma GraphQL “coeur”, commun à tous les noeuds, et un système de déclaration d’extensions GraphQL pour permettre aux noeuds d’étendre le fonctionnalité sans imposer ça dans le schéma des clients communs au réseau
2 J'aimes

Ok alors je l’implémenterai :slight_smile:

Ben justement c’est ce que je propose :slight_smile: Un schéma de base commun, qui sera le seul utilisé par les clients. Après GraphQL permet d’exposer des champs en plus sans casser les requetes existantes, donc on est libre de rajouter des champs pour des besoins spécifiques, ça ne vous impactera pas :slight_smile:

J’ai lu sur la doc officielle de GraphQL que si on rajoute un champ ça reste rétro compatible avec les versions précédentes du schéma, c’est peut être ça que tu appelle extension de requête ?

Pour cela j’exposerai un endpoint versionné conformément au format des endpoints WS2Pv2 :slight_smile:
Ce qui signifie que le jours on on fait des changements cassants dans l’api j’exposerai 2 endpoinbts: 1 pour GVA v1 et un pour GVA v2 :slight_smile:

Je mettrai a jours tout le schéma d’un coup en prenant en compte les retours de @Junidev et @Inso, ej ferai ça quand j’aurais le temps, peut etre demain soir :slight_smile:

Ça me paraît bien.

Pour les valeurs par défaut, je ne sais pas si c’est possible…

Sachant qu’un développeur qui bosse sur un projet déjà existant passe 75% de son temps à lire du code et 25% à coder, le code doit être LA documentation.
C’est pour cela que tout doit être explicite, sauf en cas de perte de performances où l’on ajoute alors un commentaire expliquant le bloc de code parfois incompréhensible mais ultra optimisé.

Avant de coder dans le vide une architecture, une spécification minimum s’impose (comme une todo liste avant de faire les courses). Surtout pour un travail collectif.

Mes recommandations sont aussi :

  • Explicite plutôt que implicite. (le code EST la doc)
  • Éviter le null, c’est mieux (et jamais de null sur un champ booléen !)
  • Pagination OBLIGATOIRE sur les requêtes de listes avec un maximum pour le nombre d’éléments à recevoir. Sinon, l’application s’auto-détruit avec le temps où l’aide d’un attaquant.

Bref je suis plutôt un adepte du Craftmanship

2 J'aimes