Una introducción a REST

Nota del editor: Este artículo fue publicado originalmente en inglés. Con la aprobación del autor, el equipo de IDUG ha creado la traducción que a continuación se presenta.

 

Si han estado al pendiente del progreso de Db2 a lo largo de los últimos años entonces este es un tema que han observado que se menciona muchas veces. Esto es particularmente cierto en la zona de Db2 para z/OS, lo que aparece ser la dirección hacia soporte directo para servicios REST (RESTful services).

Esperamos traerles toda la información reciente sobre el estado del soporte de REST a través de la familia de Db2. Sin embargo, en este artículo vamos a describir un poco sobre el concepto de REST y cómo es que es posible proveer soporte de REST para datos en Db2 desde antes de que el producto tuviera la funcionalidad incluida.

 

Orígenes de REST

Aunque solo ha ganado la atención en los años recientes, la terminología de REST existe desde el año 2000 cuando fue el título de la tesis acacémica de Roy Fielding en la Universidad de California (el título original es “Architectural Styles and the Design of Network-based Software Architectures”. En un sentido amplio, es un estilo de arquitectura de cualquier aplicación hypermedia sobre la red, pero usualmente este término se usa como un estilo de construcción de servicios web.

El atractivo de las técnicas REST se debe en gran parte a que produce aplicaciones más ligera y fáciles de mantener que las arquitecturas previas de servicios web que se basan en tecnologías WSDL y SOAP.

Su adopción ha sido acelerada por el incremento en los dispositivos móviles, los cuales dependen de servicios REST para satisfacer el constante incremento en necesidades de información.

¿Qué es REST?

Cada vez que hagan una búsqueda de este término, lo primero que van a encontrar es que el significado de REST es “Representational State Transfer”, y para ser honesto, esta definición no dice absolutamente nada a los lectores.

El estilo de arquitectura REST describe 6 reglas a las que una aplicación debe atenerse para poder ser considerada RESTful. Estas son:

Cliente-servidor

Interfaz uniforme

Stateless

Cacheable

Sistema en capas

Código bajo demanda (opcional)

Lo que esto significa en la práctica es lo siguiente

- El uso de URIs consistentes para especificar recursos que pueden ser encontrados

- El uso de verbos HTTP (GET, PUT, POST, DELETE) para invocar las diferentes acciones sobre estos recursos

- El regreso de información a través de las llamadas es en el formato JSON

De esta manera, un URI podría definir un empleado en la base de datos

http://myserver.com/employee/123

Si se invoca utilizando la función GET, esto podría regresar un documento JSON que describe al empleado con el ID 123. Llamar el mismo URI con la función POST podría insertar o actualizar este recurso.

Los URIs también pueden ser definidos para colecciones de información. Por ejemplo

http://myserver.com/employees

Lo anterior podría permitir una interfaz con la colección de los empleados. Ejecutar GET sobre este URI podría regresar una lista de todos los empleados. Ejecutar POST sobre la misma URI podría agregar un nuevo empleado, donde los datos enviados pueden proveer los detalles del empleado que se van a agregar.

Los URIs frecuentemente representan recursos de bases de datos, pero esto no es necesariamente el caso. Por ejemplo, en la situación anterior podría existir una tabla EMPLOYEE con un campo llave donde el empleado tiene un valor de 123. En muchos casos sencillos esto podría ser, y en efecto muchos frameworks que proveen características REST obligan este tipo de relación. Pero el mapeo podría ser mucho más complejo que esto.

Frameworks con soporte de REST

No pasó mucho tiempo para que varios frameworks de desarrollo web agregaran soporte para funcionalidad REST. Justamente cada framework de desarrollo web de estos días ofrece soporte de REST.

Uno de los primeros frameworks en agregar soporte REST fue Ruby on Rails: Agregó soporte REST en Rails 1.2 en Enero del año 2007. El soporte de REST en Rails todavía es uno de los más elegantes y uno de los más comentados (como podría esperarse de Rails). Por ejemplo, el siguiente fragmento de código agrega un conjunto de rutas REST para empleados.

 

ActionController::Routing::Routes.draw do |map|
  map.resources :employees
end

Rails se extiende más allá de este soporte sencillo – cuando ustedes generan un modelo con sus facilidades de generación por defailt, todo el ruteo REST es generado por default. También permite una adición fácil a rutas de procesamiento especial si son requeridas -

 

ActionController::Routing::Routes.draw do |map|
  map.resources :employees, :collection => { :recent => :get }
end

Esto agrega una rutina extra /employees/recent, invocada utilizando GET, y hacia las rutas por default. Este framework permite mucho más y todo de una manera muy sencilla. Podría ser cierto el mencionar que mucha de la implementación del soporte de REST en muchos frameworks fue influenciado gracias a la implementación en Rails. Tanto así que cuando observamos los frameworks de otros lenguajes como node.js, encontrarán una clasificación de qué tanto se acercan a Rails.

Debido a que muchos frameworks proveen soporte de Db2, también fue el caso de que es sencillo agregar servicios REST sobre bases de datos de Db2. En el resto de este ejemplo, vamos a utilizar un framework de este tipo para producir servicios REST sobre una base de datos de Db2.

 

Implementación de REST utilizando Node.js / Express.js

En este ejemplo, hemos elegido demostrar cómo implementar algunos servicios sencillos REST utilizando el framework basado en Javascript node.js, en conjunto con Express.js

Node.js es una elección muy popular para ejecución de Javascript del lado del servidor, y es frecuentemente utilizado para producir aplicaciones ligeras de una manera rápida. Express.js es el framework estándar para aplicaciones web con node.js y se utiliza como la base para frameworks más sofisticados.

En este ejemplo, vamos a crear nuestra aplicación en Linux. Hemos instalado un servidor Db2 utilizando técnicas estándar y también hemos instalado node.js utilizando el administrador de paquetes de Linux. Esto no solamente instala el soporte básico de node.js sino que también provee npm, que es el administrador de paquetes de node.js.

Lo primero que tenemos que hacer es instalar Express a través de npm (incluyendo el generador de facilidades, Express generator facilities).

sudo npm install -g express-generator

Esto instala Express y su generador global dentro de NPM (instalar módulos NPM globalmente significa que estarán disponibles para todas las aplicaciones node.js en lugar de ser instalados para cada aplicación).

En este punto estamos listos para comenzar a definir nuestra aplicación. Anteriormente creamos un directorio llamado apps y nos hemos dirigido a dicha ubicación para ejecutar el comando que crea una aplicación llamada myapp.

express -e -v ejs myapp

Aquí he hecho la elección personal del template EJS templating system para vistas, ya que encuentro que es la mejor opción disponible. Express ofrece una elección de sistemas de templates, lo que ofrece diferentes maneras de incrustar salidas JavaScript en los resultados.

Esto generará una aplicación básica en el directorio myapp. Lo primero que necesitamos hacer es introducir el soporte de Db2 dentro de la aplicación. Hacemos esto al editar el archivo package.json y agregamos una línea con los detalles del driver Db2 que necesitamos.

 

ibm_db”: “>= 2.2.1”

Normalmente en este punto simplemente podríamos ejecutar “npm install” y esto descargaría e instalaría todos los paquetes NPM que necesitamos para satisfacer las dependencias. Para Db2 esto incluso descargaría y después estaría configurando un cliente IBM Data Server para su uso con node.js. Sin embargo, la versión cliente que se descarga con este proceso no es la más reciente (no estoy seguro por qué no se ha actualizado esto) y de ahí, es una mejor opción apuntar a una versión del cliente más actualizada que instalamos nosotros mismos. Para esto tenemos que crear la variable de ambiente IBM_DB_HOME antes de ejecutar “npm install”

 

export IBM_DB_HOME=/home/db2inst1/sqllib;npm install
> ibm_db@2.2.1 install /home/philip/apps/myapp/node_modules/ibm_db
> node installer/driverInstall.js
 
IBM_DB_HOME environment variable have already been set to -> /home/db2inst1/sqllib
 
Downloading of clidriver skipped - build is in progress...
 
make: Entering directory '/home/philip/apps/myapp/node_modules/ibm_db/build'
  CXX(target) Release/obj.target/odbc_bindings/src/odbc.o
  CXX(target) Release/obj.target/odbc_bindings/src/odbc_connection.o
  CXX(target) Release/obj.target/odbc_bindings/src/odbc_statement.o
  CXX(target) Release/obj.target/odbc_bindings/src/odbc_result.o
  SOLINK_MODULE(target) Release/obj.target/odbc_bindings.node
  COPY Release/odbc_bindings.node
make: Leaving directory '/home/philip/apps/myapp/node_modules/ibm_db/build'
 
npm notice created a lockfile as package-lock.json. You should commit this file.
added 155 packages in 15.626s

Para este caso en realidad estamos apuntando a una instancia local de Db2, pero podríamos apuntar hacia un cliente local instalado.

En este punto estamos listos para probar la aplicación básica. Necesitamos entrar a db2profile antes de ejecutar “npm start”. Esto arranca una aplicación que entonces podemos acceder a través de http://localhost:3000 y que mostrará un mensaje sencillo: “Express : welcome to Express”.

A continuación se muestra la estructura de la aplicación -

philip@philip-desktop:~/apps/airbasejs$ ls -l
total 68
-rw-rw-r--   1 philip philip  1256 Feb  1 20:19 app.js
drwxr-xr-x   2 philip philip  4096 Feb  1 20:19 bin
drwxrwxr-x 145 philip philip  4096 Feb  1 20:21 node_modules
-rw-rw-r--   1 philip philip   352 Feb  1 20:20 package.json
-rw-rw-r--   1 philip philip 39209 Feb  1 20:21 package-lock.json
drwxr-xr-x   5 philip philip  4096 Feb  1 20:19 public
drwxr-xr-x   2 philip philip  4096 Feb  1 20:19 routes
drwxr-xr-x   2 philip philip  4096 Feb  1 20:19 views

Debido a que estamos interesados en las facilidades de REST, el subdirectorio routes es de especial interés para nosotros. Dentro de él encontraremos dos archivos index.js y users.js. El contenido de routes/index.js se muestra a continuación -

 

var express = require('express');
var router = express.Router();
 
/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});
 
module.exports = router;

Este es el script que se encarga de las transformaciones de los varios URIs dentro de la funcionalidad que cada URI soporta. Es más laborioso que Ruby on Rails, pero el proceso es obvio. Cuando el URI raíz es invocado con la instrucción GET, éste muestra los resultados al generar la vista “index” (archivo views/index.ejs). Podemos editar los contenidos de este archivo index y ver los resultados instantáneamente.

Lo que queremos hacer es agregar una nueva ruta REST hacia el archivo index.js para mostrar algunos datos de Db2 -

var express = require('express');
var router = express.Router();
 
/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});
 
/* Add DB2 Test */
router.get('/db2test', function(req,res) {
  const ibmdb = require('ibm_db');
  ibmdb.open("DATABASE=SAMPLE;HOSTNAME=localhost;UID=db2inst1;PWD=xxxxxxxx;PORT=50000;PROTOCOL=TCPIP",
    (err,conn) => {
      if (err) return console.log(err);
      conn.query('SELECT * FROM DEPT',
        (err,data) => {
           if (err) console.log(err);
           else {
             console.log(data);
             res.render('db2test', {
               title: "Db2 Test",
               data: data
             });
       }
     conn.close(function() {
       console.log('done');
     });
    });
  });   
  // res.render('db2test', { title: 'DB2 Test' });
});     
 
module.exports = router; 

Lo que hemos hecho es agregar soporte para un nuevo URL /db2test, también a nivel GET. Esto ejecuta un simple SELECT de la tabla DEPT en la base de datos SAMPLE y regresa los datos de la página web en formato JSON.

Esto es un ejemplo bastante sencillo, pero puede ser extendido con facilidad. Si queremos manejar POST necesitamos trabajar sobre router.post en lugar de router.get.

Existen muchos frameworks y librerías que hacen este proceso más fácil y menos repetitivo para implementar recursos, además de que hay una gran variedad de abstracciones de bases de datos para hacer la vida más sencilla. De hecho, un problema con node.js es que existen tantas librerías y frameworks que ofrecen diferentes soluciones que es difícil hacer una elección. Tal vez hay algo que debe ser mencionado sobre el mundo de Ruby on Rails.

Resumen

Hemos intentado de describir brevemente lo que es REST, y ofrecer algo de contexto. Después mostramos cómo es posible crear servicios RESTful sobre Db2 sin nada más que las librerías de desarrollo estándar. Esperamos que este artículo haya sido de utilidad.

 

 

1 Like
Recent Stories
Un nuevo capítulo de IDUG en México

Una introducción a REST

Partition By Growth Table Spaces - Partición 1, el comienzo