SOAP vs REST, diferentes formas de se comunicar.
A troca de mensagens entre aplicações permite que sistemas, desenvolvidos em diferentes plataformas, sejam compatíveis e se comuniquem. Tal comunicação pode ser dada de forma universal, por intermédio de formatos como XML, JSON, CSV, dentre outros. Serviços WEB por sua vez, podem fornecer um conjunto de padrões e rotinas que permitam esta comunicação. Tais rotinas denominadas como Interface de Programação de Aplicação (API) são definidas por duas abordagens diferentes de transmissão, possibilitando esta comunicação entre aplicações WEB: SOAP e REST.
SOAP (simple object access protocol) é um protocolo de requisitos específicos, mantido pela World Wide Web Consortium (W3C). Oferece segurança integrada e transações em conformidade, normalmente atendendo à necessidades empresariais, devido à segurança, atomicidade, consistência, isolamento e durabilidade (ACID), que por sua vez, é um conjunto de propriedades para assegurar transações confiáveis de bancos de dados.
Devido ao fato de ser um protocolo, regras integradas são impostas, aumentando a complexidade e overhead no transporte de dados. Tal abordagem utiliza o formato XML para envio e recebimento de mensagens, e pode ser descrito pela definição WSDL, descrevendo o início e fim de um serviço WEB.
REST (representational state transfer) por sua vez, é um conjunto de diretrizes que oferece uma implementação flexível. São leves e ideais para contextos mais modernos, como o desenvolvimento de aplicações mobile e serverless.
Trata-se de um conjunto de princípios arquiteturais e não de um protocolo, sendo assim, tem regras mais claras, leves e fáceis de configurar, diminuindo o overhead na troca de mensagens e permitindo a utilização de diversos padrões para isso, tais como o JSON, XML, CSV, dentre outros.
Aproximadamente 70% das aplicações hoje, utilizam a abordagem Rest para se comunicar.
A seguir, abordaremos duas aplicações simples, providas pela comunicação em SOAP, e que forneça um adapter para uma API Rest. A aplicação servidora, proverá comunicação com uma base de dados H2 em JPA e disponibilizará uma API em SOAP, que através de um arquivo XSD, irá gerar um WSDL, permitindo tal comunicação. Já a aplicação cliente, se comunicará em SOAP com a servidora através do WSDL gerado e proverá uma API em Rest para se comunicar com outros meios.
Os projetos utilizam a dependência wsdl4j em seus arquivos de compilação:
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
</dependency>
Aplicação Servidora:
O domínio do serviço web será definido por um arquivo XSD e será exposto automaticamente como um WSDL, permitindo trabalhar com requisições em XML:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://ksgprod.com/soap-poc"
xmlns:tns="http://ksgprod.com/soap-poc"
elementFormDefault="qualified">
<xs:element name="InsertCustomerRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="CustomerDetail" type="tns:CustomerDetail"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="InsertCustomerResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="status" type="tns:Status"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="GetCustomerDetailRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="id" type="xs:int"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="GetCustomerDetailResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="CustomerDetail" type="tns:CustomerDetail"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="GetAllCustomerDetailRequest">
<xs:complexType>
</xs:complexType>
</xs:element>
<xs:element name="GetAllCustomerDetailResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="CustomerDetail" type="tns:CustomerDetail" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="DeleteCustomerRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="id" type="xs:int"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="DeleteCustomerResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="status" type="tns:Status"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:simpleType name="Status">
<xs:restriction base="xs:string">
<xs:enumeration value="SUCCESS"/>
<xs:enumeration value="FAILURE"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="CustomerDetail">
<xs:sequence>
<xs:element name="id" type="xs:int" />
<xs:element name="name" type="xs:string"/>
<xs:element name="phone" type="xs:string"/>
<xs:element name="email" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
Para isso, é necessário importá-lo na estrutura de pasta resources da aplicação servidora e configurar o pom.xml desta aplicação, informando o caminho do arquivo e a estrutura de pacotes a ser gerado os objetos convertidos (binding):
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.14.0</version>
<executions>
<execution>
<id>Customer</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<schemaLanguage>WSDL</schemaLanguage>
<generatePackage>br.com.ksgprod.soap.wsdl</generatePackage>
<schemaDirectory>${project.basedir}/src/main/resources</schemaDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
As classes serão geradas em tempo de compilação, partindo do arquivo XDS importado, através do plugin: jaxb2-maven-plugin.
Uma vez startada a aplicação servidora, poderemos acessar o WSDL através do caminho: http://localhost:8080/ws/customers.wsdl
A geração do WSDL só será possível após criar e configurar nossa aplicação provedora dos serviços web. Para isso, vamos começar pelo arquivo de configuração: WebServiceConfiguration
@EnableWs: permite habilitar a aplicação Spring para serviços web.
Além disso, precisaremos definir nosso MessageDispatcherServlet como um Bean, que servirá como um servlet para o envio simplificado de mensagens web, ao passo que terá a função de identificar os endpoints específicos do SOAP web service:
@Bean
public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext context) { MessageDispatcherServlet mds = new MessageDispatcherServlet();
mds.setApplicationContext(context);
mds.setTransformWsdlLocations(true);
return new ServletRegistrationBean<MessageDispatcherServlet>(mds, "/ws/*");
}
Outro Bean, não menos importante que precisaremos implementar, será o nosso XsdSchema, que permitirá enfim, gerar o WSDL. Precisaremos descriminar o caminho de origem para o arquivo XSD importado:
@Bean
public XsdSchema customerSchema() { return new SimpleXsdSchema(new ClassPathResource("customer-information.xsd"));}
Algumas definições para o WSDL deverão ser passadas através do XsdSchema, tais como:
PortType: Funciona como uma interface para o WSDL, provendo as regras para o contrato dos serviços da sua API.
LocationUri: Defini o endereço de acesso aos serviços.
Os endpoints da nossa aplicação servidora serão expostos na controller. Algumas ressalvas são importantes para melhor compreensão deles:
Namespace: Torna o XML único e exclusivo;
Element names: Define os elementos de request e response do XML;@Endpoint: Define a classe como um endpoint, suportando os serviços criados pelo XSD;
@PayloadRoot: Permite descriminar o namespace e localpart, mapeando o XML definido através do XSD;
@RequestPayload: Possibilita conversão em objetos Java, do XML recebido;
@ResponsePayload: Possibilita conversão dos objetos Java, no XML de resposta;
Aplicação Cliente:
Sendo assim, podemos construir a aplicação cliente, que por sua vez, importará o WSDL, permitindo se comunicar via SOAP com a aplicação servidora. No pom.xml da aplicação cliente, precisaremos configurar a URL do WSDL gerado, assim como a estrutura de pacotes para as classes convertidas:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.14.0</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaLanguage>WSDL</schemaLanguage>
<generatePackage>br.com.ksgprod.soap.wsdl</generatePackage>
<schemas>
<schema>
<url>http://localhost:8080/ws/customers.wsdl</url>
</schema>
</schemas>
</configuration>
</plugin>
</plugins>
</build>
Para as requisições SOAP feitas pela nossa aplicação cliente à servidora, implementaremos um cliente de requisições SOAP estendendo da WebServiceGatewaySupport, permitindo acesso aos serviços WEB.
Para a nossa aplicação cliente, também precisaremos de algumas configurações. Primeiramente, teremos que instanciar a classe Jaxb2Marshaller como Bean, setando como contexto, o apontamento para a coleção de objetos de domínio gerados através do WSDL, fornecido pela aplicação servidora:
@Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("br.com.ksgprod.soap.wsdl");
return marshaller;
}
O marshaller usará tais objetos de domínio para serializar e desserializar os dados fornecidos pelo XML das requisições SOAP, em POJOs.
Também precisamos instanciar um Bean para o nosso cliente de requisições, informando a URI do serviço fornecido pela aplicação servidora:
@Bean
public CustomerClient customerClientMarshaller(Jaxb2Marshaller marshaller) {
CustomerClient client = new CustomerClient();
client.setDefaultUri(defaultUri);
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
return client;
}
Vimos então neste tutorial uma breve abordagem na utilização de APIs SOAP e Rest para comunicação entre aplicações WEB. Até a próxima!
Referências:
https://www.ibm.com/docs/pt-br/integration-bus/10.0?topic=services-what-is-soap
https://www.ibm.com/docs/pt-br/rsas/7.5.0?topic=standards-soap
https://www.redhat.com/pt-br/topics/integration/whats-the-difference-between-soap-rest
https://www.soapui.org/learn/api/soap-vs-rest-api/
https://spring.io/guides/gs/producing-web-service/
https://spring.io/guides/gs/consuming-web-service/
https://www.baeldung.com/spring-boot-soap-web-service