2008-10-07 9 views
7

Mi situación es la siguiente:¿Cuál es la mejor práctica para definir un servicio de jabón (operación genérica o específica)?

Tengo una base de datos normalizada, en la que tengo información geográfica sobre los aeropuertos. La estructura es:

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

Ahora quiero que los usuarios administren estos datos, sin darles acceso directo a la base de datos. Necesitamos ofrecer esta interfaz de administración a través de un servicio web.

Ahora, cuando se trata de diseñar el servicio, nos encontramos con la discusión sobre cómo definir las operaciones. Se nos ocurrió con diferentes soluciones:

Solución A: operaciones específicas

Para cada una de las cuatro mesas (aeropuerto, ciudad, país, continente) definimos 3 operaciones:

  • de inserción
  • obtener
  • actualización

Esto daría lugar a 12 operaciones con 2 objetos de solicitud/respuesta = 24 objetos

Para crear un aeropuerto nuevo con todas las dependencias, se necesitarían al menos 4 solicitudes.

Solución B: genérico

Hay solamente una operación, que se controla a través de parámetros. Esta operación puede crear todo lo necesario para administrar la base de datos.

La operación decidiría qué debe hacerse y lo ejecutará. Si se produce un error, revertirá todo.

==> 1 Operación = 2 petición altamente complejo/respuesta-objetos

Solución C: encontrarse en el medio 1

Una operación genérica por mesa, que es capaz de ejecutar obtener, insertar , actualizar, al igual que la solución B, pero se centró en una tabla cada uno.

==> 4 = 8 operaciones complejas petición/respuesta de objetos

Solución D: encontrarse en el medio 2

Una operación genérica por acción (obtener, insertar, eliminar), que puede trabajar en cada tabla y resolver dependencias.

==> 3 operaciones = 6 solicitud ligeramente más complejo/respuesta-objetos

Ejemplo

Dado que esta era bastante abstracto, hier un ejemplo simplificado para la solicitud de objetos para la creación (JFK/New York/EE.UU./América del Norte):

Solución A:

Solicitud 1/4:

<insertContinent>North America</insertContinent> 

Solicitud 2/4:

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

Solicitud 3/4:

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

Solicitud 4/4:

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

Solución B:

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

Solución C:

Solicitud 1/4:

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

Solicitud 2/4:

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

Solicitud 3/4:

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

Solicitud 4/4:

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

Solución D: Solicitud 1/1:

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

Solución D parece bastante elegante para mí, por lo tanto, trató de poner esto en XSD:

Código:

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

Una solicitud correspondiente sería el siguiente aspecto siguiente:

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

Ahora mi pregunta: ¿Es esto realmente la mejor solución disponible? ¿Es suficiente el XSD para entender qué está pasando?

Respuesta

5

Presumiblemente está escribiendo una capa de protocolo que comprenderá sus diferentes tipos de mensajes. También necesitará una capa de aplicación para analizar el contenido del mensaje. Los diferentes enfoques que menciona cambiarán la carga de análisis entre estas dos capas.Entonces, por ejemplo:

Solución A: La capa de protocolo hace todo el análisis y devuelve los datos y el comando. La capa de aplicación solo puede usar los datos. Esto también se conoce como el patrón RPC.

Pros: Puede validar sus mensajes. Puede asignar mensajes directamente a las llamadas a la aplicación.

Contras: Si necesita hacer un cambio en la interfaz, su protocolo cambia.

Solución B: La capa de protocolo devuelve dos valores y un comando. La capa de aplicación debe usar el comando para analizar los valores en tipos.

Pros: El protocolo nunca cambia.

Contras: No se pueden validar los mensajes. El código de tu aplicación es más complicado.

Solución C: La capa de protocolo devuelve dos tipos conocidos y un comando que debe analizarse. La capa de aplicación solo puede analizar el comando y usar los datos.

Beneficios: No se me ocurre ninguno, parece que no es un muy buen compromiso.

Contras: Deja el análisis parcialmente hecho.

Solución D: La capa de protocolo devuelve tipos conocidos (la forma en que lo implementó) y un comando genérico. La capa de aplicación debe mirar los datos que recibe y convertir el comando genérico en un comando específico. Esto es similar a la arquitectura REST.

Pros: Las llamadas son operaciones distintas para que pueda, por ejemplo, obtener respuestas de caché.

Contras: La complejidad en la capa de aplicación

El modelo REST por lo general se pone en práctica de manera diferente que usted ha descrito. Utiliza los mensajes HTTP GET, POST, PUT, DELETE para comunicar documentos arbitrarios. Los parámetros se dan como parte de la URL. Así, por ejemplo:

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

convierte

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

O si está utilizando HTTP se convierte en una petición POST a una URL aeropuerto con un parámetro de la ciudad con el contenido de ser información sobre el aeropuerto. Tenga en cuenta que algo de esto se vuelve más claro con más datos compilados en los que tiene múltiples elementos y tipos mixtos. Por ejemplo, si desea enviar la abreviatura del aeropuerto, el nombre largo y la altitud.

Creo que la arquitectura REST podría funcionar bastante bien para la interfaz que describes. Mientras todo lo que necesite hacer es soportar las operaciones CRUD. Hay muchos sitios que le darán los pros y los contras del estilo arquitectónico REST.

Personalmente prefiero el estilo RPC (Solución A) con algunos atributos REST-ful. Quiero que el protocolo haga el trabajo de análisis y valide los mensajes. Esta es la forma típica en que las personas implementan las interfaces de servicio web SOAP.

Su interfaz puede parecer simple hoy pero mañana uno de sus clientes le va a pedir una nueva llamada que no se ajusta tan bien al modelo REST y se encontrará encajando en los cuatro mensajes existentes.

1

Esta es una vieja pregunta, y estoy seguro de que el servicio se ha escrito hace mucho tiempo, pero quería contribuir con una respuesta de todos modos.

El enfoque REST sería definir un recurso aeropuerto, como este:

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

O bien, si desea utilizar una compatible con el explorador microformato:

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

Este recurso sería ubicado en un URI como /airports/JFK, que se recuperaría con un método GET, actualizado con un método PUT y eliminado con un método DELETE.

En un diseño como este, el URI /airports/ representaría un recurso contenedor para todos los aeropuertos de la base de datos, y URIs como /airports/?city=New+York y /airports/?country=USA habría filtros en el recipiente para devolver un subconjunto de los aeropuertos. Ambos serían GET métodos, y los recursos contendrían una lista de recursos aeroportuarios como se definió anteriormente, ya sea en su totalidad (ya que son pequeños) o con algunos atributos útiles y el href que apunta al recurso completo para cada aeropuerto .

Finalmente, agregar un nuevo recurso podría ser un método PUT en el URI completo del aeropuerto, o un método POST en /airports/. En ambos casos, el cuerpo de la solicitud es el recurso del aeropuerto como se muestra arriba. La diferencia entre los métodos es quién decide el URI final para el aeropuerto: el cliente decide por PUT y el servicio decide por POST. El que use depende de si sus clientes pueden o no determinar razonablemente el URI correcto. Por lo general, el servicio decide porque los URI contienen un identificador único numérico y el servicio tiene que elegir eso.

Ahora, por supuesto, su pregunta original era sobre SOAP, no REST. Continuaría y configuraría un diseño RESTful como lo describí, luego describiré mis recursos como tipos complejos usando XSD y un servicio SOAP con acciones que duplican las operaciones GET, PUT, DELETE y POST del servicio RESTful. Esto le dará el equivalente 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) 
Cuestiones relacionadas