50 votes

Quel est le meilleur moyen de gérer le contrôle de version à l'aide du protocole JSON?

Je suis normalement écrit de toutes les parties du code en C# et lors de la rédaction des protocoles qui sont sérialisés-je utiliser FastSerializer qui sérialise/désérialise les classes rapide et efficace. Il est également très facile à utiliser, et assez simple à faire "versioning", c'est à dire de gérer les différentes versions de la sérialisation. La chose que j'ai l'habitude d'utiliser, ressemble à ceci:

public override void DeserializeOwnedData(SerializationReader reader, object context)
{
    base.DeserializeOwnedData(reader, context);
    byte serializeVersion = reader.ReadByte(); // used to keep what version we are using

    this.CustomerNumber = reader.ReadString();
    this.HomeAddress = reader.ReadString();
    this.ZipCode = reader.ReadString();
    this.HomeCity = reader.ReadString();
    if (serializeVersion > 0)
        this.HomeAddressObj = reader.ReadUInt32();
    if (serializeVersion > 1)
        this.County = reader.ReadString();
    if (serializeVersion > 2)
        this.Muni = reader.ReadString();
    if (serializeVersion > 3)
        this._AvailableCustomers = reader.ReadList<uint>();
}

et

public override void SerializeOwnedData(SerializationWriter writer, object context)
{            
    base.SerializeOwnedData(writer, context);
    byte serializeVersion = 4; 
    writer.Write(serializeVersion);


    writer.Write(CustomerNumber);
    writer.Write(PopulationRegistryNumber);            
    writer.Write(HomeAddress);
    writer.Write(ZipCode);
    writer.Write(HomeCity);
    if (CustomerCards == null)
        CustomerCards = new List<uint>();            
    writer.Write(CustomerCards);
    writer.Write(HomeAddressObj);

    writer.Write(County);

    // v 2
    writer.Write(Muni);

    // v 4
    if (_AvailableCustomers == null)
        _AvailableCustomers = new List<uint>();
    writer.Write(_AvailableCustomers);
}

Donc facile d'ajouter de nouvelles choses, ou de modifier la sérialisation complètement si l'on choisit de le faire.

Cependant, je veux maintenant utiliser JSON pour des raisons qui ne sont pas pertinentes ici =) je suis actuellement en utilisant DataContractJsonSerializer et je suis maintenant à la recherche d'un moyen d'avoir la même souplesse que j'ai à l'aide de la FastSerializer ci-dessus.

Donc la question est: quelle est la meilleure façon de créer un protocole JSON/de sérialisation et d'être en mesure de détailler la sérialisation comme ci-dessus, de sorte que je ne vous cassez pas la sérialisation juste parce que l'autre machine n'a pas encore mis à jour leur version?

49voto

monsur Points 8340

La clé de la gestion des versions JSON est de toujours ajouter de nouvelles propriétés, et de ne jamais supprimer ou renommer des propriétés existantes. Ceci est similaire à la façon dont tampons de protocole, de gérer le versioning.

Par exemple, si vous avez commencé avec le JSON suivants:

{
  "version": "1.0",
  "foo": true
}

Et vous voulez renommer le "toto" à la propriété "bar", ne suffit pas de le renommer. Au lieu de cela, ajouter une nouvelle propriété:

{
  "version": "1.1",
  "foo": true,
  "bar": true
}

Puisque vous n'êtes jamais suppression des propriétés, les clients basée sur d'anciennes versions de continuer à travailler. L'inconvénient de cette méthode est que le JSON pouvez obtenir gonflé au fil du temps, et vous devez continuer à maintenir anciennes propriétés.

Il est également important de définir clairement vos "bord" des cas à vos clients. Supposons que vous disposez d'un tableau de propriété appelée "fooList". Le "fooList" propriété peut prendre les valeurs possibles suivantes: il n'existe pas/non défini (la propriété n'est pas physiquement présent dans l'objet JSON, ou qu'elle existe et est mis à "undefined"), null, liste vide ou une liste d'un ou de plusieurs valeurs. Il est important que les clients à comprendre comment se comporter, en particulier dans l'indéfini/null/vide.

Je vous recommande aussi la lecture sur la façon sémantique gestion des versions des œuvres. Si vous introduisez une sémantique schéma de gestion des versions de vos numéros de version, puis vers l'arrière compatible modifications peuvent être faites sur une version mineure des limites, à tout casser, des modifications peuvent être faites sur une version majeure de limite (à la fois les clients et les serveurs s'entendent sur la même version majeure). Si ce n'est pas une propriété de l'JSON lui-même, c'est utile pour communiquer les types de modifications d'un client doit s'attendre lorsque les changements de version.

16voto

shashankaholic Points 1989

La bibliothèque gson basée sur Java de Google offre un excellent support de gestion de version pour json. Cela pourrait s'avérer très pratique si vous envisagez d'aller en Java.

Il y a un tutoriel agréable et facile ici .

9voto

Lie Ryan Points 24517

Il n'a pas d'importance ce que la sérialisation de protocole que vous utilisez, les techniques de version de l'Api sont généralement les mêmes.

En général, vous devez:

  1. une façon pour le consommateur, à communiquer au producteur de la version de l'API, il accepte (même si ce n'est pas toujours possible)
  2. un moyen pour le producteur d'incorporer des informations de contrôle de version pour les données sérialisées
  3. un rétro-compatible stratégie pour gérer des domaines inconnus

Dans une API web, généralement la version de l'API que le consommateur accepte est incorporé dans l'en-tête Accept (par exemple, Accept: application/vnd.myapp-v1+json application/vnd.myapp-v2+json signifie que le consommateur peut gérer soit la version 1 et la version 2 de l'API) ou, moins fréquemment, dans l'URL (par exemple, https://api.twitter.com/1/statuses/user_timeline.json). Ceci est généralement utilisé pour les versions majeures (c'est à dire en arrière des modifications incompatibles). Si le serveur et le client ne correspond pas Accepter d'en-tête, puis l'échec de la communication (ou le produit à base du meilleur effort ou de secours à un défaut de base du protocole, en fonction de la nature de la demande).

Le producteur génère alors un sérialisé les données de la version demandée, puis d'intégrer ces informations de version dans les données sérialisées (par exemple, comme un champ nommé version). Le consommateur doit utiliser les informations de version intégré dans les données afin de déterminer comment analyser les données sérialisées. Les informations de version dans les données doivent également contenir une petite version (c'est à dire pour la compatibilité ascendante des changements), généralement les consommateurs devraient être en mesure d'ignorer la version mineure de l'information et de toujours traiter correctement les données, bien que la compréhension de la version mineure peut permettre au client de faire des hypothèses sur la façon dont les données doivent être traitées.

Une stratégie commune pour gérer des domaines inconnus comme quoi le HTML et les CSS sont analysées. Lorsque le client voit un des domaines inconnus, ils devraient l'ignorer, et lorsque l'on manque de données d'un champ que le client attend, il doit utiliser une valeur par défaut, en fonction de la nature de la communication, vous pouvez également spécifier certains champs sont obligatoires (c'est à dire des zones manquantes est considéré comme erreur fatale). Les champs ajoutés dans les versions mineures doivent toujours être champ facultatif; version mineure pouvez ajouter des champs optionnels ou de modifier les champs sémantiques, tant que c'est compatible, alors que la version majeure pouvez supprimer les champs ou ajouter des champs obligatoires ou de modifier les champs sémantiques dans une arrière incompatible manière.

Dans un extensible format de sérialisation (comme JSON ou XML), les données doivent être auto-descriptif, en d'autres mots, les noms de champs doivent toujours être stockées avec les données; vous ne devez pas compter sur les données spécifiques disponibles sur des postes spécifiques.

6voto

Adrian Salazar Points 2573

N'utilisez pas de DataContractJsonSerializer, comme le nom le dit, les objets qui sont traités par cette classe aura à:

a) Être marqué avec [DataContract] et [DataMember] attributs.

b) Être strictement conformes à la définition de "Contrat" qui est, rien de moins et rien de plus qu'elle est définie. Supplémentaires ou manquants [DataMember] pour la désérialisation pour lever une exception.

Si vous voulez être assez souple, puis utilisez le JavaScriptSerializer si vous voulez aller de l'option la plus économique... ou de l'utilisation de cette bibliothèque:

http://json.codeplex.com/

Cela vous donnera suffisamment de contrôle sur votre sérialisation JSON.

Imaginez que vous avez un objet à ses débuts.

public class Customer
{ 
    public string Name;

    public string LastName;
}

Une fois sérialisé, il ressemblera à ceci:

{ Nom: "Jean", LastName: "Doe" }

Si vous modifiez votre définition de l'objet à ajouter / supprimer des champs. La désérialisation se déroule sans heurts, si vous utilisez, par exemple, JavaScriptSerializer.

public class Customer
{ 
    public string Name;

    public string LastName;

    public int Age;
}

Si yo tentative de dé-sérialiser la dernière json à cette nouvelle classe, aucune erreur ne sera générée. Le truc, c'est que votre nouveau champs seront définis à leurs valeurs par défaut. Dans cet exemple: "l'Âge" sera mis à zéro.

Vous pouvez inclure dans vos propres conventions, un champ présent dans tous vos objets, qui contient le numéro de version. Dans ce cas, vous pouvez faire la différence entre un champ vide ou une version inconsistance.

Donc permet de dire: Vous avez votre Client de classe v1 sérialisé:

{ Version: 1, LastName: "Doe", Name: "John" }

Vous souhaitez désérialiser un Client v2 exemple, vous aurez:

{ Version: 1, LastName: "Doe", Name: "John", Age: 0}

Vous pouvez en quelque sorte, de détecter quels sont les domaines de votre objet sont d'une certaine manière fiable et ce qui ne l'est pas. Dans ce cas, vous savez que votre v2 instance de l'objet est à venir à partir d'un v1 instance de l'objet, de sorte que le champ de l'Âge ne devrait pas être digne de confiance.

J'ai dans l'esprit que vous devez utiliser également un attribut personnalisé, par exemple "MinVersion", et la marque de chaque champ avec la version minimale prise en charge, de façon à ce que vous obtenez quelque chose comme ceci:

public class Customer
{ 
    [MinVersion(1)]
    public int Version;

    [MinVersion(1)]
    public string Name;

    [MinVersion(1)]
    public string LastName;

    [MinVersion(2)]
    public int Age;
}

Puis plus tard, vous pouvez accéder à cette méta-données et de faire tout ce que vous pourriez avoir besoin avec que.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X