2008-10-07 12 views
7

Ma situation est la suivante:Quelle est la meilleure pratique pour définir un service de savon (opération générique vs opération spécifique)?

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

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

Maintenant je veux laisser les utilisateurs administrer ces données, sans leur donner un accès direct à la base de données. Nous devons offrir cette interface d'administration via un service web. Maintenant, quand il s'agit de concevoir le service, nous sommes tombés sur la discussion sur la façon de définir les opérations. Nous sommes venus avec des solutions différentes:

Solution A: opérations spécifiques

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

  • insert
  • obtenir
  • mise à jour

Cela aboutirait à 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, qui est contrôlé par les paramètres. Cette opération est capable de créer tout ce qui est nécessaire pour administrer la base de données.

L'opération détermine ce qui doit être fait et l'exécute. Si une erreur survient, elle va tout annuler.

==> 1 Fonctionnement = 2 objets de demande de réponse très complexe/

Solution C: Rendez-vous au milieu 1

Une opération générique par table, qui est capable d'exécuter obtenir, insérer , mise à jour, tout comme la solution B, mais concentrée sur une table chacun.

==> 4 opérations = 8 objets de demande de réponse complexe/

Solution D: Rendez-vous au milieu 2

Une opération générique par action (obtenir, insérer, supprimer), qui peut travailler sur chaque table et résoudre les dépendances.

==> 3 opérations = 6 légèrement plus complexe demande/réponse-objets

Exemple

Comme c'était plutôt abstraite, hier un exemple simplifié de la demande-objets pour créer (JFK/Nouveau York/Etats-Unis/Amérique du Nord):

Solution A:

Demande 1/4:

<insertContinent>North America</insertContinent> 

Demande 2/4:

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

Demande 3/4:

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

4/4 Demande:

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

Solution B:

Demande 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:

Demande 1/4:

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

Demande 2/4:

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

Demande 3/4:

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

4/4 Demande:

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

Solution D: demande 1/1:

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

Solution D semble assez élégante pour moi, donc j'ai essayé de mettre ce 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 doit ressembler à suit:

<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> 

Ma question: Est-ce vraiment la meilleure solution disponible? Le XSD est-il suffisant pour comprendre, que se passe-t-il?

Répondre

5

On suppose que vous êtes en train d'écrire une couche de protocole qui comprendra vos différents types de message. Vous aurez également besoin d'une couche d'application pour analyser le contenu du message. Les différentes approches que vous mentionnez vont déplacer le fardeau de l'analyse entre ces deux couches.Par exemple:

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

Les avantages: Vous pouvez valider vos messages. Vous pouvez mapper les messages directement aux appels d'application. Inconvénients: Si vous devez modifier l'interface, votre protocole change.

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.

Pour: 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 de protocole renvoie deux types connus et une commande qui doit être analysée. La couche application peut simplement analyser la commande et utiliser les données. Les avantages: Je ne peux pas penser à tout, semble pas un très bon compromis. Inconvénients: Laisse l'analyse seulement partiellement effectuée.

Solution D: La couche de protocole renvoie les types connus (la façon dont vous l'avez implémentée) et une commande générique. La couche application doit regarder 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 de sorte que vous pouvez, par exemple, obtenir des réponses en cache.

Inconvénients: La complexité de la couche d'application

Le modèle REST est généralement mis en œuvre différemment 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 le cadre de 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, il devient une requête POST à ​​une URL de l'aéroport avec un param de la ville avec le contenu étant d'informations sur l'aéroport. Notez que cela devient plus clair avec des données plus compliquées lorsque vous avez plusieurs éléments et types mixtes. Par exemple si vous voulez envoyer l'abréviation de l'aéroport, le nom long et l'altitude.

Je pense que l'architecture REST pourrait très bien fonctionner pour l'interface que vous décrivez. Tant que tout ce que vous devez 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 quelques attributs REST-FULL. Je veux que le protocole fasse le travail d'analyse et valide les messages. C'est généralement la manière dont les utilisateurs implémentent les interfaces de service Web SOAP.Votre interface peut sembler simple aujourd'hui, mais demain, l'un de vos clients vous demandera un nouvel appel qui ne correspond pas si bien au modèle REST et vous vous retrouverez coincé dans les quatre messages existants.

1

Ceci est une vieille question, et je suis sûr que le service a été écrit il y a longtemps, mais je voulais apporter une réponse de toute façon.

L'approche RESTful serait de définir une ressource de l'aéroport, comme celui-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 le navigateur:

<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é à un URI comme /airports/JFK, qui serait récupéré avec une méthode GET, mis à jour avec une méthode PUT, et supprimé avec une méthode DELETE.

Dans un design comme celui-ci, l'URI /airports/ représenterait une ressource de conteneur pour tous les aéroports de la base de données, et comme URIs /airports/?city=New+York et /airports/?country=USA seraient les filtres sur le récipient pour retourner un sous-ensemble des aéroports. Ces deux méthodes seraient GET et les ressources contiendraient une liste de ressources aéroportuaires telle que définie ci-dessus, soit en totalité (puisqu'elles sont petites), soit avec quelques attributs utiles et href indiquant la ressource complète pour 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 requête est la ressource aéroportuaire comme indiqué ci-dessus. La différence entre les méthodes est de savoir qui décide de l'URI finale pour l'aéroport: le client décide pour PUT et le service décide pour POST. Lequel vous utilisez dépend si vos clients peuvent raisonnablement déterminer le bon URI. Habituellement, le service décide parce que les URI contiennent un identifiant unique numérique et que le service doit le choisir.

Maintenant, bien sûr, votre question initiale portait sur SOAP, pas sur REST. Je voudrais aller de l'avant et configurer un design RESTful comme je l'ai décrit, puis décrire mes ressources comme des types complexes en utilisant XSD et un service SOAP avec des actions qui dupliquent les opérations 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) 
Questions connexes