Qual é a melhor prática na definição de um serviço de sabão (operação específica vs. genérico)?

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

  •  05-07-2019
  •  | 
  •  

Pergunta

A minha situação é a seguinte:

Eu tenho um banco de dados normalizado, no qual eu segurar a informação geográfica sobre aeroportos. A estrutura é:

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

Agora eu quero permitir que os usuários Administrar esses dados, sem lhes dar acesso direto ao banco de dados. Precisamos oferecer esta interface de administração através de um serviço web.

Agora, quando se trata de conceber o serviço, que correu para a discussão sobre como definir as operações. Nós veio com soluções diferentes:

Solução A: operações específicas

Para cada um dos quatro mesas (aeroporto, cidade, país, continente) definimos 3 operações:

  • Inserir
  • get
  • update

Isso levaria a 12 operações com 2 objetos de solicitação / resposta = 24 objetos

Para criar um novo aeroporto todos com todas as dependências, pelo menos 4 pedidos seria necessário.

Solução B: genérico

Há apenas uma operação, que é controlada através de parâmetros. Esta operação é capaz de criar tudo o necessário para administrar o banco de dados.

A operação iria decidir o que precisa ser feito e executa-lo. Se um occures erro, ele irá reverter tudo.

==> 1 Operação 2 = altamente complexas de pedido / resposta-objetos

Solução C: Encontro no meio 1

Uma operação genérica por tabela, que é capaz de executar get, insert, update, apenas como solução B, mas focado em uma mesa de cada um.

==> 4 = 8 operações pedido complexo / resposta-objetos

Solução D: Conheça no meio 2

Uma operação genérica por ação (obter, insert, delete), que pode trabalhar em cada mesa e resolver as dependências.

==> 3 = 6 operações pedido ligeiramente mais complexo / resposta-objetos

Exemplo

Uma vez que este foi um pouco abstrato, hier um exemplo simplificado para solicitar-objetos para a criação (JFK / Nova York / EUA / América do Norte):

Solução A:

Request 1/4:

<insertContinent>North America</insertContinent>

Request 2/4:

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

Request 3/4:

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

Request 4/4:

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

Solução B:

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

Solução C:

Request 1/4:

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

Request 2/4:

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

Request 3/4:

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

Request 4/4:

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

Solução D: Pedido 1/1:

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

Solução D parece bastante elegante para mim, por isso eu tentei colocar isso em 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>

Uma solicitação correspondente seria semelhante a seguir:

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

Agora a minha pergunta: Esta é realmente a melhor solução disponível? É o suficiente XSD de entender, o que está acontecendo?

Foi útil?

Solução

Provavelmente, você está escrevendo uma camada de protocolo que vai entender seus tipos diferentes de mensagens. Você também vai precisar de uma camada de aplicação para analisar o conteúdo da mensagem. As diferentes abordagens que você menciona irá transferir a carga de analisar entre estas duas camadas. Assim, por exemplo:

Solução A : A camada de protocolo faz toda a análise e retorno dos dados e de comando. A camada de aplicação pode apenas utilizar os dados. Isso também é conhecido como o padrão RPC.

Prós: Você pode validar suas mensagens. Você pode mapear mensagens diretamente para chamadas de aplicação.

Contras:. Se você precisar de fazer uma mudança para a interface, as alterações do protocolo

<> fortes Solução B : O protocolo de camada de retornos dois valores e um comando. A camada de aplicação deve usar o comando para analisar os valores em tipos.

Prós:. O protocolo nunca muda

Contras: Você não pode validar mensagens. O código do aplicativo é mais complicado.

Solução C : camada de protocolo retorna dois tipos conhecidos e um comando que deve ser analisado. A camada de aplicação pode apenas analisar o comando e usar os dados.

Prós:. Eu não consigo pensar em nenhum, parece que não um compromisso muito bom

Contras:. Folhas a análise apenas parcialmente feito

Solução D : A camada de protocolo retorna tipos conhecidos (o jeito que você implementou) e um comando genérico. A camada de aplicação deve olhar para os dados que recebe e converter o comando genérico em um comando específico. Isto é similar à arquitetura REST.

Prós: As chamadas são operações distintas para que você possa, por exemplo, cache de obter respostas

.

Contras: Complexidade na camada de aplicação

O modelo RESTO é normalmente implementado de forma diferente do que você tem delineado. Ele usa HTTP GET, POST, PUT, Excluir mensagens para comunicar documentos arbitrários. Parâmetros são dados como parte do URL. Assim, por exemplo:

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

se torna

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

Ou se você estiver usando HTTP torna-se uma solicitação POST para um URL aeroporto com um param da cidade com o conteúdo a ser informações sobre o aeroporto. Note-se que alguns dos isto torna-se mais clara com os dados mais compliated onde você tem vários elementos e tipos mistos. Por exemplo, se você quiser enviar a abreviatura aeroporto, nome longo e altitude.

Eu acho que a arquitetura restante poderia funcionar muito bem para a interface que você descreve. Enquanto tudo o que você precisa fazer é apoiar as operações CRUD. O muitos sites que lhe dará os prós e contras do estilo arquitectónico REST.

Pessoalmente eu prefiro o estilo RPC (Solução A) com alguns atributos de REST-ful. Eu quero o protocolo para fazer o trabalho de análise e validar as mensagens. Isto é tipicamente como as pessoas implementar interfaces de serviços web SOAP.

Sua interface pode parecer simples hoje, mas amanhã um de seus clientes vai pedir-lhe para uma nova chamada que não se encaixa no modelo RESTO tão bem e você vai encontrar-se cunha-lo nas quatro mensagens existentes.

Outras dicas

Esta é uma questão de idade, e eu tenho certeza que o serviço tem sido escrito há muito tempo, mas eu queria contribuir com uma resposta de qualquer maneira.

A abordagem RESTful seria definir um recurso aeroporto, como esta:

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

Ou, se você quiser usar um microformato compatível com o navegador:

<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 seria localizado em um URI como /airports/JFK, que seria recuperado com um método GET, atualizado com um método PUT e excluídos com um método DELETE.

Em um projeto como este, o /airports/ URI representaria um recurso contêiner para todos os aeroportos do banco de dados, e URIs como /airports/?city=New+York e /airports/?country=USA seria filtros no recipiente para retornar um subconjunto dos aeroportos. Ambos estes seriam métodos GET, e os recursos que contêm uma lista de recursos para o aeroporto como definido acima, na íntegra (uma vez que eles são pequenos) ou com alguns atributos úteis e o href que aponta para o recurso completo para cada aeroporto .

Finalmente, a adição de um novo recurso poderia ser um método PUT em plena URI do aeroporto, ou um método POST em /airports/. Em ambos os casos, o corpo do pedido é o recurso aeroporto como mostrado acima. A diferença entre os métodos é quem decide o URI final para o aeroporto: o cliente decide por PUT eo serviço decide por POST. Qual deles você usar depende se ou não seus clientes podem razoavelmente determinar a URI direita. Normalmente, o serviço decide porque os URIs contêm um identificador único numérico eo serviço tem que escolher isso.

Agora é claro que a sua pergunta original sobre SOAP, não REST. Gostaria de ir em frente e criar um design RESTful como já descrito, em seguida, descrever meus recursos como tipos complexos usando XSD e um serviço de SOAP com ações que duplicam o GET, PUT, DELETE e operações POST do serviço RESTful. Isto lhe dará o 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)
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top