Quelle est la meilleure pratique pour définir un service de savon (opération générique ou opération spécifique)?

StackOverflow https://stackoverflow.com/questions/180572

  •  05-07-2019
  •  | 
  •  

Question

Ma situation est la suivante:

J'ai une base de données normalisée dans laquelle je conserve des informations géographiques sur les aéroports. La structure est la suivante:

airport --is in--> city --is in--> country --is in--> continent

Je souhaite maintenant permettre aux utilisateurs d’administrer ces données sans leur donner un accès direct à la base de données. Nous devons proposer cette interface d'administration via un service Web.

Maintenant, quand il s’agit de concevoir le service, nous avons discuté de la définition des opérations. Nous avons proposé différentes solutions:

Solution A: opérations spécifiques

Pour chacune des quatre tables (aéroport, ville, pays, continent), nous définissons 3 opérations:

  • insérer
  • obtenir
  • mettre à jour

Cela conduirait à 12 opérations avec 2 objets requête / réponse = 24 objets

Pour créer un tout nouvel aéroport avec toutes les dépendances, au moins 4 demandes seraient nécessaires.

Solution B: générique

Il n'y a qu'une seule opération contrôlée par des paramètres. Cette opération est capable de créer tout le nécessaire pour administrer la base de données.

L'opération déciderait de ce qui doit être fait et l'exécutera. Si une erreur se produit, tout sera annulé.

== > 1 opération = 2 objets de requête / réponse très complexes

Solution C: réunion au milieu 1

Une opération générique par table, capable d'exécuter get, insert, update, exactement comme la solution B, mais centrée sur une table.

== > 4 opérations = 8 objets de requête / réponse complexes

Solution D: réunion au milieu 2

Une opération générique par action (get, insert, delete), qui peut fonctionner sur chaque table et résoudre les dépendances.

== > 3 opérations = 6 objets de requête / réponse légèrement plus complexes

Exemple

Etant donné qu’il s’agissait d’un texte plutôt abstrait, voici un exemple simplifié d’objets de requête pour la création (JFK / New York / États-Unis / Amérique du Nord):

Solution A:

Requête 1/4:

<insertContinent>North America</insertContinent>

Demande 2/4:

<insertCountry continent="North America">USA</insertCountry>

Requête 3/4:

<insertCity country="USA">New York</insertCity>

Requête 4/4:

<insertAirport city="New York">JFK</insertAirport>

Solution B:

Requête 1/1:

<action type="insertCountry" parent="North America">USA</action>
<action type="insertAirport" parent="New York">JFK</action>
<action type="insertContinent" parent="">North America</action>
<action type="insertCity" parent="USA">New York</action>

Solution C:

Requête 1/4:

<countryAction type="insert" parent="North America">USA</countryAction>

Demande 2/4:

<airportAction type="insert" parent="New York">JFK</airportAction>

Requête 3/4:

<continentAction type="insert" parent="">North America</continentAction >

Requête 4/4:

<cityAction type="insert" parent="USA">New York</cityAction >

Solution D: Demande 1/1:

<insert airport="JFK" city="New York" country="USA" continent="North America" />

La solution D me semble plutôt élégante, alors j’ai essayé de mettre cela dans XSD:

Code:

<complexType name="NewContinent">
    <sequence>
        <element name="NAME" type="string"></element>
    </sequence>
</complexType>

<complexType name="NewCountry">
    <sequence>
        <element name="ISOCODE" type="string"></element>
        <element name="NAME" type="string"></element>
        <choice>
            <element name="newCONTINENT" type="tns:NewContinent"></element>
            <element name="CONTINENT" type="string"></element>
        </choice>
    </sequence>
</complexType>

<complexType name="NewCity">
    <sequence>
        <element name="IATA" type="string"></element>
        <element name="NAME" type="string"></element>
        <choice>
            <element name="COUNTRY" type="string"></element>
            <element name="newCOUNTRY" type="tns:NewCountry"></element>
        </choice>
    </sequence>

</complexType>

<complexType name="NewAirport">
    <sequence>
        <element name="IATA" type="string"></element>
        <element name="NAME" type="string"></element>
        <choice>
            <element name="CITY" type="string"></element>
            <element name="newCITY" type="tns:NewCity"></element>
        </choice>
    </sequence>

</complexType>

Une demande correspondante devrait alors ressembler à ceci:

<complexType name="Request">
    <choice>
        <element name="AIRPORT" type="tns:NewAirport"></element>
        <element name="CITY" type="tns:NewCity"></element>
        <element name="COUNTRY" type="tns:NewCountry"></element>
        <element name="CONTINENT" type="tns:NewContinent"></element>
    </choice>
</complexType>

Maintenant ma question: S'agit-il vraiment de la meilleure solution disponible? La XSD est-elle suffisante pour comprendre ce qui se passe?

Était-ce utile?

La solution

Vous écrivez probablement une couche de protocole qui comprendra vos différents types de messages. Vous aurez également besoin d'une couche d'application pour analyser le contenu du message. Les différentes approches que vous avez mentionnées déplaceront le fardeau de l'analyse entre ces deux couches. Ainsi, par exemple:

Solution A : la couche de protocole effectue toute l'analyse et renvoie les données et la commande. La couche d'application peut simplement utiliser les données. Ceci est également connu sous le nom de modèle RPC.

Avantages: vous pouvez valider vos messages. Vous pouvez mapper des messages directement aux appels d'applications.

Inconvénients: si vous devez modifier l'interface, votre protocole est modifié.

Solution B : la couche de protocole renvoie deux valeurs et une commande. La couche d'application doit utiliser la commande pour analyser les valeurs en types.

Avantages: le protocole ne change jamais.

Inconvénients: vous ne pouvez pas valider les messages. Le code de votre application est plus compliqué.

Solution C : la couche protocole renvoie deux types connus et une commande qui doit être analysée. La couche d'application peut simplement analyser la commande et utiliser les données.

Avantages: je ne peux en penser à aucun, semble ne pas être un très bon compromis.

Inconvénients: ne laisse l'analyse que partiellement effectuée.

Solution D : la couche de protocole renvoie les types connus (comme vous l'avez implémentée) et une commande générique. La couche d'application doit examiner les données qu'elle reçoit et convertir la commande générique en une commande spécifique. Ceci est similaire à l'architecture REST.

Avantages: les appels sont des opérations distinctes afin que vous puissiez, par exemple, obtenir des réponses en cache.

Inconvénients: complexité dans la couche d'application

Le modèle REST est généralement mis en œuvre différemment de ce que vous avez décrit. Il utilise les messages HTTP GET, POST, PUT, DELETE pour communiquer des documents arbitraires. Les paramètres sont donnés dans l'URL. Ainsi, par exemple:

<insert airport="JFK" city="New York" country="USA" continent="North America" />

devient

<insert URL="airport?city=Chicago">ORD</insert>

Ou, si vous utilisez HTTP, cela devient une demande POST adressée à une URL d’aéroport avec un paramètre de la ville dont le contenu est une information relative à l’aéroport. Notez qu'une partie de ceci devient plus claire avec des données plus compliquées dans lesquelles vous avez plusieurs éléments et types mélangés. Par exemple, si vous souhaitez envoyer l’abréviation, le nom long et l’altitude de l’aéroport.

Je pense que l'architecture REST pourrait très bien fonctionner pour l'interface que vous décrivez. Tant que tout ce que vous avez à faire est de soutenir les opérations CRUD. Il existe de nombreux sites qui vous donneront les avantages et les inconvénients du style architectural REST.

Personnellement, je préfère le style RPC (solution A) avec certains attributs REST-FUL. Je veux que le protocole effectue l'analyse syntaxique et valide les messages. C’est généralement ainsi que les utilisateurs implémentent les interfaces de service Web SOAP.

Votre interface a peut-être l'air simple aujourd'hui, mais demain, l'un de vos clients vous demandera un nouvel appel qui ne convient pas si bien au modèle REST et vous vous retrouverez à le coincer dans les quatre messages existants.

Autres conseils

C'est une vieille question et je suis sûr que le service a été écrit il y a longtemps, mais je voulais quand même apporter une réponse.

L’approche RESTful consisterait à définir une ressource aéroportuaire, telle que celle-ci:

<airport href="/airports/JFK">
    <name>JFK</name>
    <city>New York</city>
    <country>USA</country>
    <continent>North America</continent>
</airport>

Ou, si vous souhaitez utiliser un microformat compatible avec les navigateurs:

<div class="object airport" href="/airports/JFK">
    <ul class="attributes"> 
        <li class="name">JFK</li>
        <li class="city">New York</li>
        <li class="country">USA</li>
        <li class="continent">North America</li>
    </ul>
</div>

Cette ressource serait située à un URI tel que / airports / JFK , qui serait récupéré avec une méthode GET , mis à jour avec un PUT et supprimé avec une méthode DELETE .

Dans une telle conception, l'URI / airports / représenterait une ressource conteneur pour tous les aéroports de la base de données, et des URI tels que / airports /? city = New + York et / airports /? country = USA serviraient de filtres sur le conteneur pour renvoyer un sous-ensemble des aéroports. Ces deux méthodes seraient des méthodes GET , et les ressources contiendraient une liste des ressources aéroportuaires telles que définies ci-dessus, soit en totalité (car elles sont petites), soit avec quelques attributs utiles et le code . href qui pointe vers la ressource complète de chaque aéroport.

Enfin, l'ajout d'une nouvelle ressource peut être une méthode PUT sur l'URI complet de l'aéroport ou une méthode POST sur / airports / . . Dans les deux cas, le corps de la demande est la ressource aéroport, comme indiqué ci-dessus. La différence entre les méthodes est de savoir qui décide de l'URI final de l'aéroport: le client décide de PUT et le service choisit de POST . Le type que vous utilisez dépend si vos clients peuvent ou non déterminer raisonnablement le bon URI. Habituellement, le service décide, car les URI contiennent un identifiant unique numérique et le service doit le choisir.

Bien entendu, votre question initiale portait sur SOAP, pas sur REST. Je voudrais ensuite configurer une conception RESTful comme je l'ai décrite, puis décrire mes ressources en tant que types complexes utilisant XSD et un service SOAP avec des actions dupliquant GET , PUT , DELETE et POST du service RESTful. Cela vous donnera l'équivalent RPC de:

class Airport
    has String name
    has String city
    has String country
    has String continent
    method void update(name, city, country, continent)
    method void delete()

class AirportList
    method Airport[] get(opt name, opt city, opt country, opt continent)
    method void add(name, city, country, continent)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top