Mostrando entradas con la etiqueta SOAP. Mostrar todas las entradas
Mostrando entradas con la etiqueta SOAP. Mostrar todas las entradas

jueves, 10 de octubre de 2013

Servicios web (webservices) con SOAP sobre CodeIgniter

(Continuación del artículo Servicios web (webservices) con REST sobre CodeIgniter)

SOAP

En la primera parte de este artículo te comenté sobre el uso de REST sobre CodeIgniter usando la biblioteca “CodeIgniter Rest Server”. A continuación de hablaré sobre el trabajo con la biblioteca nusoap para la implementación de webservices con SOAP sobre CodeIgniter.

La nusoap (versión 0.9.5) puedes descargarla en [2]. En el artículo [1] puedes ver un guía excelente de la instalación de nusoap sobre CodeIgniter. Básicamente es igual a la instalación del Rest Server: copias la carpeta lib de la instalación de nusoap para la carpeta application/libraries (en mi caso le cambié el nombre a la carpeta lib por nusoap_lib), y en ese mismo nivel creas una biblioteca interfaz que hace una llamada a la nusoap, así:

class Nusoap_library
{
function Nusoap_library()
{
require_once('nusoap_lib/nusoap'.EXT);
}
}

Sencilla de instalar. Ahora vamos a crear servicios: siguiendo el mismo tutorial [1] hacemos un controlador con su constructor, un index y un servicio que suma dos números:

class Soapserver extends CI_Controller
{
function Soapserver()
{
parent::__construct();
$this->load->library("Nusoap_library"); //cargando mi biblioteca
$this->nusoap_server = new soap_server();
$this->nusoap_server->configureWSDL("SOAP Server", $ns);
$this->nusoap_server->wsdl->schemaTargetNamespace = $ns;

//registrando funciones
$input_array = array ('a' => "xsd:string", 'b' => "xsd:string");
$return_array = array ("return" => "xsd:string");
$this->nusoap_server->register('addnumbers', $input_array, $return_array, "urn:SOAPServerWSDL", "urn:".$ns."/addnumbers", "rpc", "encoded", "Addition Of Two Numbers");
}

function index()
{
function addnumbers($a,$b)
{
$c = $a + $b;
return $c;
}

$this->nusoap_server->service(file_get_contents("php://input"));
}
}

Solamente tenemos dos métodos principales, el constructor y el index. En el constructor cargo mi biblioteca que a su vez llama a la nusoap, y configuro el servidor de nusoap. A continuación registro la función addnumbers (debajo del comentario “registrando funciones”). Ese grupo de código dice que la función recibe dos variables strings llamadas a y b, y que retorna otro string. Con $this->nusoap_server->register se registra la función especificando los parámetros de entrada y salida y un conjunto de parámetros que ahora no tienen importancia para este artículo. El último de ellos es un comentario o documentación del servicio addnumbers. Podrás ver que la función se implementa dentro del index, y después de esta función (y de todas las que adiciones) llamas a $this->nusoap_server->service.

Hasta aquí el servidor SOAP debe funcionar sin problemas. Podrás ver tus servicios publicados accediendo a tu sitio http://sitio/index.php/soapserver. Para consumir los mismos prepara otro controlador (por ejemplo soapserver_testing) y un método como este:

function test()
{
$params = array(
'a' => 2,
'b' => 3,
);

$result = $this->nusoap_client->call('addnumbers', $params);
}

Al cual accederías normalmente por el link http://sitio/index.php/soapserver_testing/test.

El problema que nos presenta SOAP sobre REST es que hay que declarar las variables de entrada y salida de cada función, y registrar cada función, lo cual es más pesado pero por supuesto genérico (recuerda que REST formatea cualquier resultado de BD directamente hacia un XML, JSON, etc. sin importar si los valores son enteros, cadenas, etc).

El gran problema con SOAP es a la hora de retornar consultas de la BD que implica la existencia de arreglos, objetos, tipos de datos complejos más allá de los string e int… para esto, debes construir la estructura de los objetos que retornarás. En el siguiente código te pongo un ejemplo completo, por pasos:

1. Creamos una clase que será el resultado del servicio. Utilizando la misma que creé para los servicios REST como te puse en la primera parte de este artículo, sería algo así (fuera de la clase Soapserver):

class Response_students
{
public $responseCode = 100;
public $responseMessage = 'Error desconocido';
public $data = NULL;
}

2. Declaramos un tipo de dato “Student” en el constructor de Soapserver (debajo del comentario “registrando funciones”):

$this->nusoap_server->wsdl->addComplexType(
"Student", //nombre del tipo de dato
"complexType", //tipo complejo
"struct", //en este caso struct por ser un objeto
"all", //no interesante ahora
"", //no interesante ahora
array( //miembros de la clase Student (columnas en la BD)
"NAME"=>array("name"=>"NAME", "type"=>"xsd:string"),
"AGE"=>array("name"=>"AGE", "type"=>"xsd:int")
)
);

3. Creamos un tipo de dato que será un arreglo de “Students”:

$this->nusoap_server->wsdl->addComplexType(
'Students_array',
'complexType',
'array', //tipo array porque es un arreglo de objetos
'',
'SOAP-ENC:Array', //estructura equivalente en SOAP
array(),
array(
array(
'ref' => 'SOAP-ENC:arrayType',
'wsdl:arrayType' => 'tns:Student[]' //contiene un array de Student
)
),
'tns:Student
);

4. Creamos el objeto respuesta de mi servicio, correspondiente a la clase Response_students del paso 1. La clase contiene un código que es un número, un mensaje string, y un objeto de tipo students_array creado en 3, que a su vez es un arreglo de Student creado en 2:

$this->nusoap_server->wsdl->addComplexType(
'Response_students',
'complexType',
'struct',
'all',
'',
array
('responseCode' => array('type' => 'xsd:int'),
'responseMessage' => array('type' => 'xsd:string'),
'data' => array('type' => 'tns: Students_array')
)
);

5. Registramos un método que va a devolver los estudiantes de un aula (class_room):

$this->nusoap_server->register(
"get_students", //nombre de la función
array('class_room' => "xsd:int"), //parámetros de entrada
array("return" => "tns: Response_students"), //objeto de salida
$ns,
$ns . "#get_students",
"rpc",
"encoded",
"Servicio que retorna los estudiantes de un aula"
);

6. Implementamos la función-servicio que retorna los estudiantes, dentro del index:

function get_students($class_room)
{
$CI = &get_instance();
$CI->load->model('students_model');
$students = $CI->students_model->get_students_of_room($class_room);

$result = new Response_students();

if (!empty($students))
{
$result->responseCode = 0;
$result->responseMessage = 'Estudiantes encontrados';
$result->data = array();
foreach ($students as $value)
$result->maintenances_data[] = $value;
}
return $result;
}

Listo. Recuerda que esto no es un tutorial, por eso no he explicado a profundidad todo el código. Basta con que te hayas llevado la idea de cómo es el funcionamiento de la biblioteca nusoap.

Espero que te hayan servido ambas partes del artículo, la relacionada con REST y esta con SOAP. Mi principal conclusión es que realmente hacen honor a los comentarios que te encuentras en internet: con REST implementas rápidamente cualquier servicio y él se encarga de formatearlo a XML u otras estructuras, pero es poco genérico; SOAP es más genérico pero es realmente complicado usarlo para estructuras complejas. De todas maneras, según el sistema que quieras implementar, las bibliotecas que te describí te pueden ser útiles para seguir incorporando funcionalidades a tus sitios implementados sobre CodeIgniter.

Referencias:

[1] SOAP Server In CodeIgniter using NuSOAP PHP Toolkit.htm

http://www.php-guru.in/2013/soap-server-in-codeigniter-using-nusoap-library/

[2] Descarga de biblioteca nusoap:

http://sourceforge.net/projects/nusoap/

{ Leer Más }


viernes, 17 de mayo de 2013

Servicios de datos con WSO2 para resolver el acceso a datos.

En la entrada Introducción a Spring JDBC como solución a los problemas de uso e JDBC en proyectos productivos veíamos cómo podíamos implementar el acceso a datos usando Spring JDBC y luego en la entrada Sustituyendo la capa de persistencia de Spring JDBC por Spring + Hibernate hacíamos lo mismo pero usando Spring + Hibernate + Anotaciones.

En esta entrada entonces quiero ilustrarles un posible problema y la solución que se le puede dar.

Asumamos que somos los desarrolladores de una aplicación donde una de las entidades es “capítulo” y que hemos creado un DAO para dicha entidad. Esto permite que se pueda acceder desde cualquier lugar de la aplicación a los datos de “capítulo” a través del DAO correspondiente, pero que pasa si otra aplicación por algún motivo justificado necesita acceder a esos mismos datos. ¿Cómo se hace?

Soluciones pueden existir 2 o 3, pero en mi caso quiero exponerles una que he usado bastante y que consiste en crear un servicio de acceso a datos que exponga a través de SOAP o REST un conjunto de operaciones CRUD sobre dicha entidad. Pueden ver esta solución en la siguiente imagen.

image

Como se puede ver en la imagen el “Sistema propio” bien puede optar por acceder a la entidad directamente en la BD o puede hacerlo vía el servicio web. El resto de las aplicaciones tiene ahora acceso a los datos de la entidad “Capitulo” de una forma controlada gracias al uso del AS o el DSS.

Las ventajas de este enfoque son:

  • Se desarrolla más rápido el acceso a la entidad, con tan solo 3 minutos tienes creado un servicio web que cumple con todos los estándares del Stack WS-*.
  • Se puede brindar acceso a los datos de la entidad a otras aplicaciones sin requerir nuevas implementaciones.
  • La aplicación dueña de la entidad puede seguir accediendo de la manera tradicional o empezar a hacerlo desde el servicio web. Aquí si el servicio web cumple con la misma interface con que cumplía la implementación usando JDBC o Hibernate no debe haber problema para hacer el cambio.
  • Al usar la plataforma de WSO2 al servicio se le pueden incorporar facilidades para la autenticación, autorización y auditorias que aseguren un correcto acceso a los recursos.
  • El servicio expuesto es interoperable e independiente de la tecnología, o sea que se puede consumir desde cualquier lenguaje de programación.

Desventajas:

  • Por lo general se dice que el acceso a los servicios es más lento que si se accede directamente a los recursos, y es algo cierto. Lo que se debe determinar es si la latencia introducida afecta la experiencia del usuario final o del sistema. Aquí temas como el cacheo de la información juegan un papel fundamental.
  • A los desarrolladores no les gusta tener fuera de su control funcionalidades del sistema y en este caso el servicio está fuera del sistema en un servidor externo, lo que requiere un acceso diferente a la BD.
  • Si solo se requiere un servicio web para 1 entidad, la solución dada puede ser como el ejemplo de usar un cañón para matar un mosquito. Algunas otras variantes como RMI o incluso Spring Web Services puede ser más interesante de implementar. Aunque si la empresa se encuentra dentro de una iniciativa SOA o en alguna implementación de una solución de integración si tiene mucho sentido implementar un servicio de acceso a datos. Esto último lo pueden ver en la siguiente entrada Introducción a SOA y BPM.

Para aquellos que quieran ver cómo implementar un servicio de acceso a datos usando la suite de WSO2 en solo 3 minutos los invito a que vean este enlace.

El servicio que se crea por esa vía contiene las operaciones CRUD básicas y lo bueno es que luego se puede modificar para ajustarlo a nuestras necesidades. Si alguien quiere hacerlo desde cero y no usar la funcionalidad de “Generate” pues lo puede hacer sin ningún problema.

En otras entradas estaremos viendo más de estos temas.

Palabras claves: servicio web, servicio de acceso a datos, WSO2, AS, DSS, SOAP.

{ Leer Más }


IconIconIcon