UNIDAD 11: Servicios Web
eugeniaperez.es
eugeniaperez.es
11.1 Spring y Soap
Un servicio web constituye un método que es accedido a través de la red. Es decir, se puede acceder a él de manera remota desde otra máquina que tenga conectividad con la máquina que aloja el servicio.
El término API sirve para identificar una serie de servicios web disponibles y relacionados entre sí. Ejemplos son Google Maps, ebay, Amazon, etc.
¡Reutilización de código!
eugeniaperez.es
11.1 Spring y Soap
Por lo tanto una API representa un catálogo de métodos públicos que podemos utilizar desde nuestras aplicaciones.
Quiero desarrollar una web de "música" que presente información extraída de diversas APIs que me proporcionan información para tal propósito:
http://www.lastfm.es/api
http://www.lastfm.es/api/rest
eugeniaperez.es
11.1 Spring y Soap
Las dos maneras fundamentales de implementar servicios web independientemente de la tecnología son:
eugeniaperez.es
11.1 Spring y Soap
SOAP es un protocolo estándar que define cómo diferentes procesos pueden comunicarse por medio de
intercambio de datos XML.
Un mensaje SOAP es un documento XML ordinario con una estructura definida en la especificación del protocolo.
Al utilizar XML el parseo es más costoso y la comunicación entre cliente y servidor más lenta.
eugeniaperez.es
11.1 Spring y Soap
Veamos un ejemplo de cómo crear servicios Web SOAP en Spring. Para ello, descárgate el proyecto y carga complete:
https://github.com/spring-guides/gs-producing-web-service.git
eugeniaperez.es
11.1 Spring y Soap
El XSD de countries define objetos con sus atributos del WS:
<xs:element name="getCountryRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
Las peticiones (request) que consistirán en un objeto con un atributo nombre de tipo String.
eugeniaperez.es
11.1 Spring y Soap
La response devuelve un Country, que es un objeto complejo:
<xs:element name="getCountryResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="country" type="tns:country"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="country">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="population" type="xs:int"/>
<xs:element name="capital" type="xs:string"/>
<xs:element name="currency" type="tns:currency"/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="currency">
<xs:restriction base="xs:string">
<xs:enumeration value="GBP"/>
<xs:enumeration value="EUR"/>
<xs:enumeration value="PLN"/>
</xs:restriction>
</xs:simpleType>
eugeniaperez.es
11.1 Spring y Soap
Dentro del pom.xml:
Genera unas clases Java a partir de los XSD (En nuestro caso src/main/resources/countries.xsd)
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
eugeniaperez.es
11.1 Spring y Soap
Desde el proyecto: Run As -> Maven generate-sources
Se generan las anteriores clases...
Varios countries para enviar la respuesta (datos consulta)
Define el servicio web
Lanza el servicio
Genera el WSDL que es el descriptor del WS
eugeniaperez.es
11.1 Spring y Soap
Clase endpoint (define el servicio web):
@Endpoint
public class CountryEndpoint {
private static final String NAMESPACE_URI =
"http://spring.io/guides/gs-producing-web-service";
private CountryRepository countryRepository;
@Autowired
public CountryEndpoint(CountryRepository countryRepository) {
this.countryRepository = countryRepository;
}
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")
@ResponsePayload
public GetCountryResponse getCountry(@RequestPayload GetCountryRequest request) {
GetCountryResponse response = new GetCountryResponse();
response.setCountry(countryRepository.findCountry(request.getName()));
return response;
}
}
eugeniaperez.es
11.1 Spring y Soap
La clase Endpoint posee el método getCountry, que es el servicio web propiamente dicho.
Recibe un objeto GetCountryRequest y retorna un GetCountryResponse.
Es decir, genera una respuesta a partir del parámetro name de la petición: se busca en el repositorio el país que recibido y se establece la respuesta como retorno del servicio.
eugeniaperez.es
11.1 Spring y Soap
Sobre la clase WebServiceConfig que contiene la configuración, genera el WSDL y que se lanza finalmente...
Esta configuración genera como resultado un fichero WSDL: sirve para describir nuestro servicio web para que los clientes lo puedan consultar y ver así cómo deben generar las peticiones y qué tipo de respuestas pueden esperar.
eugeniaperez.es
11.1 Spring y Soap
La siguiente dependencia en el pom.xml descarga un Tomcat empotrado para servir el servicio web:
Para cambiar el puerto 8080 por defecto, en src/main/resources genero un application.properties con una entrada: server.port = 8888
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-ws</artifactId>
</dependency>
eugeniaperez.es
11.1 Spring y Soap
Finalmente se arranca la clase Application.java (Run As -> Java Application)
Y se puede visualizar la especificación del WSDL
Desde el navegador: http://localhost:8080/ws/countries.wsdl
Si cambio el puerto: http://localhost:8888/ws/countries.wsdl
eugeniaperez.es
11.1 Spring y Soap
Especificación del WSDL
eugeniaperez.es
11.1 Spring y Soap
¡¡Ahora sólo nos queda probarlo!!
No obstante, esto es un poco más complicado, ya que debemos componer un mensaje SOAP, y eso requiere de un formato XML de acuerdo a nuestro XSD.
Existen clientes que nos facilitan la tarea. Uno de ellos es SOAPUI (versión gratuita):
eugeniaperez.es
11.1 Spring y Soap
eugeniaperez.es
11.1 Spring y Soap
Se genera el esqueleto del mensaje a enviar y relleno los valores:
En CountriesRepository tendría la información a ser retornada por el servicio
Request
Response
eugeniaperez.es
11.1 Spring y Soap
La configuración tanto de los servicios como de los clientes con SOAP es mucho más compleja.
La transmisión de la información al ser en XML es más lenta y su parseo en el cliente más costosa.
Era el método tradicional anteriormente a REST, dado que antes se tendía a trabajar con XMLs.
eugeniaperez.es
11.2 Spring y Rest
Rest (Representational State Transfer) se refiere a una colección de principios para el diseño de arquitecturas web.
Rest NO es un estándar, solo un estilo de arquitectura basado en estándares:
eugeniaperez.es
11.2 Spring y Rest
Lo mejor para captar la idea de lo que supone REST es ver la anatomía de una RESTful url.
Las URLs son nominales y no verbales, y representan un recurso:
Sobre esto se realizarían variaciones en función de si es inserción, actualización, borrado, etc. En contraposición a las peticiones tradicionales (sin un fw MVC):
http://www.miapp.net/cliente/42
http://www.miapp.net/cliente.php?id=45&ac=delete
eugeniaperez.es
11.2 Spring y Rest
Se permite utilizar toda la potencia que nos ofrecen los distintos métodos HTTP, y no sólo GET y POST, que son los que se han venido usando tradicionalmente:
Esto nos permite realizar un CRUD completo a través del controlador...
eugeniaperez.es
Descarga el código en Bitbucket
Descarga el proyecto springmvc.rest del repositorio de Bitbucket:
Usuario:
Psswd:
URL: https://eugenia_perez@bitbucket.org/eugenia_perez/springmvc.rest.git
eugeniaperez.es
11.2 Spring y Rest
Desarrollo del servicio web
Antes de nada, es muy importante incorporar estas dependencias al pom:
eugeniaperez.es
11.2 Spring y Rest
Desarrollo del servicio web
No busco cambiar de
página, sino datos...
eugeniaperez.es
11.2 Spring y Rest
Consumo del servicio web desde cliente
¡Ya tenemos nuestra API Rest! -> Estas acciones pueden ser llamadas desde cualquier dispositivo con conectividad a nuestra máquina, con la simple ayuda de un cliente que sea capaz de realizar peticiones HTTP.
Por ejemplo, comenzaremos haciendo una petición mediante el navegador. Vamos a hacer una petición GET a la URL:
http://localhost:8080/springmvc/series
eugeniaperez.es
11.2 Spring y Rest
Consumo del servicio web desde cliente
Recuerda que el API Rest que se ofrece responde a:
SelectAll [GET]:
SelectById [GET]:
Insert [POST]:
Update [PUT]:
Delete [DELETE]:
http://localhost:8080/springmvc/series
http://localhost:8080/springmvc/series/id
http://localhost:8080/springmvc/series
http://localhost:8080/springmvc/series/id
http://localhost:8080/springmvc/series/id
eugeniaperez.es
11.2 Spring y Rest
Consumo del servicio web desde cliente
¿Qué acción responderá? El método get de nuestro controlador (devuelve todas las películas en BD...):
1) A través del navegador
eugeniaperez.es
11.2 Spring y Rest
Consumo del servicio web desde cliente
2) A través de un cliente REST del navegador:
Instalo el plugin de Google Advanced REST client.
Lo inicio: http://localhost:8080/springmvc/series
Se inserta en BD
eugeniaperez.es
11.2 Spring y Rest
Consumo del servicio web desde cliente
3) A través de una llamada Ajax mediante JQuery:
Mediante el fichero jsClient.html en src/main/webapp/resources.
Crea una fila por cada película retornada y la añade a la table:
$.get('http://localhost:8080/springmvc/series', function(data){
var tableData = $('table tbody');
$.each(data, function(idx, elm){
tableData.append('<tr><td>' + elm.id + '</td><td>' + elm.title + '</td><td>' + elm.dateReleased +
'</td><td>' + elm.numberOfEpisodes + '</td><td>' + elm.country + '</td></tr>')
});
});
eugeniaperez.es
11.2 Spring y Rest
Consumo del servicio web desde cliente
3) A través de una llamada Ajax mediante JQuery:
Utilizo el método PUT para actualizar el número de episodios de la serie con ID 1:
$('#updateSeries').on('click', function(){
$.ajax({
url: "http://localhost:8080/springmvc/series/1",
type: "PUT",
data: JSON.stringify({
"id" : 1,
"title" : "Better call Saul",
"numberOfEpisodes" : "100",
"dateReleased" : "2015-02-01",
"country":"USA"
}),
contentType: "application/json"
}).done(function(response){
alert(response);
});
});
eugeniaperez.es
11.2 Spring y Rest
Consumo del servicio web desde cliente
3) A través de una llamada Ajax mediante JQuery:
Para ejecutarlo:
http://localhost:8080/springmvc/resources/jsClient.html
eugeniaperez.es
11.2 Spring y Rest
Consumo del servicio web desde cliente
4) Consumo desde otras aplicaciones, como una aplicación en Java.
Aunque el escenario más común de los servicios web REST es nutrir de datos a código Javascript que corre en el cliente, estos están disponibles a cualquiera otra tecnología servidor que los invoque.
Nos descargamos el proyecto a continuación.
eugeniaperez.es
Descarga el código en Bitbucket
Descarga el proyecto restclient del repositorio de Bitbucket:
Usuario:
Psswd:
URL: https://eugenia_perez@bitbucket.org/eugenia_perez/restclient.git