Monday, April 4, 2016

Android, Heroku, Node.js para publicar un WebService REST (II)

En el Post Anterior buscábamos tener una API REST para consumir desde un dispositivo Android.

Con ese fin, construimos una API Sencilla con Heroku y Node.js que nos entregaba algunas imágenes relacionadas con el Ajedrez, un juego que amo. Las imágenes que entregaba la API eran de las piezas de Ajedrez....

Hoy vamos a dar un paso más con la API, para que entregue ejercicios (puzzles) de por ejemplo Mate en 1 jugada, Mate en dos jugadas, en tres ... y en cuatro jugadas.....  Obviamente, los ejercicios de mate en una jugada son mas sencillos que los de cuatro jugadas.... Con lo cual, podemos segmentar dentro de la API, algunos ejercicios con diferentes grados de complejidad. A su vez estas secciones podríamos discriminarlas dentro de la aplicación Android.

Comencemos

Utilizando la interesante librería http://chessboardjs.com/ armé varias posiciones de jaque mate. En este post comentaba el procedimiento. Si bien esta librería construye los tableros con Javascript. los recorté como imágenes para utilizarla en el ejercicio de Hoy.







Así es como tenemos la siguiente colección de problemas:

http://mw000561.ferozo.com/pncn/chess/post_chessboardjs/v2/index_mate_1.html

Y tenemos las imágenes que buscábamos generar, asociadas a esos problemas:


El diagrama que resalta, es uno de los "Mate en 2" que pueden dar las blancas.

Paso 01: Diseñamos las API

De forma local, el espacio de la API es el siguiente, muy intuitivo:
   
// - http://localhost:5000/chess/api/matesEn1/00
// - http://localhost:5000/chess/api/matesEn1/08
// ...
// - http://localhost:5000/chess/api/matesEn2/00
// - http://localhost:5000/chess/api/matesEn2/08
// ...
// - http://localhost:5000/chess/api/matesEn3/00
// - http://localhost:5000/chess/api/matesEn3/16
// ...
// - http://localhost:5000/chess/api/matesEn4/00
// - http://localhost:5000/chess/api/matesEn4/02

Recordemos que las imágenes están en:




La primera pregunta es ¿Como defino la función en Node.js? Ya que tiene que recibir el numero de problema que necesitamos:

Tenemos dos Posibilidades de patrones:

Para:
http://localhost:5000/chess/api/matesEn4/02

Posibilidades:
'/chess/api/matesEn1/:id'
'/chess/api/matesEn2/:id'
'/chess/api/matesEn3/:id'
'/chess/api/matesEn4/:id'

O bien, mas resumido:
'/chess/api/:mates/:id'






Código Node.js de la API REST



La lista de problemas, para simplificar lo dejo en una variable de javascript, respetando el json:
   
var mateJuagas1 = [

{ position: '5k2/4np2/5N2/8/8/B7/7K/6R1 w - - 0 1' , solution: '1. Rg8#' },
{ position: '3r4/1pk5/3pP3/2N5/8/8/2R3K1/8 w - - 0 1' , solution: '1. Nd7#' },
{ position: '3Nnr2/R2PkP2/4p3/8/8/8/7K/3R4 w - - 0 1' , solution: '1. dxe8=N#' },

{ position: '6r1/1Q3P2/5k2/5P2/5K2/8/8/8 w - - 0 1' , solution: '1. fxg8=N#' },
{ position: '8/5P2/5k2/5B2/5K2/8/8/8 w - - 0 1' , solution: '1. f8=Q#' },
{ position: 'rnb4k/6pp/8/p3N3/8/PB6/1PP4R/2K5 w - - 0 1' , solution: '1. Ng6# ' },

{ position: '4k3/3nn3/4N3/1N6/8/8/6K1/8 w - - 0 1' , solution: '1. Nd6#' },
{ position: '6k1/p1p2rpp/1q6/2p1P3/8/1Q6/PP4PP/3R3K w - - 0', solution: '1. Rd8#' },
{ position: '8/8/8/7R/3k4/2R5/1K3P2/6B1 w - - 0 1' , solution: '1. f3#' }

];
A continuación las funciones de entrada de la API, observemos que solamente aceptamos GET, y también el parámetro variable definido con :id


   
var CONST_MateEn1 = "mateEn1";
var CONST_MateEn2 = "mateEn2";
var CONST_MateEn3 = "mateEn3";
var CONST_MateEn4 = "mateEn4";

app.get('/chess/api/matesEn1/:id', function(req, res){
res.json( getJsonDiagram(CONST_MateEn1, req, res));
});

app.get('/chess/api/matesEn2/:id', function(req, res){
res.json( getJsonDiagram(CONST_MateEn2, req, res));
});

app.get('/chess/api/matesEn3/:id', function(req, res){
res.json( getJsonDiagram(CONST_MateEn3, req, res));
});

app.get('/chess/api/matesEn4/:id', function(req, res){
res.json( getJsonDiagram(CONST_MateEn4, req, res));
});

function getColeccion(col) {

if (col == CONST_MateEn1) {
return mateJuagas1;
}

if (col == CONST_MateEn2) {
return mateJuagas2;
}

if (col == CONST_MateEn3) {
return mateJuagas3;
}

if (col == CONST_MateEn4) {
return mateJuagas4;
}

return null;
}

function getJsonDiagram (col, req, res) {

var mateJuagas = getColeccion(col);

var id = req.params.id;

var jsonAA = mateJuagas[id];

var position = jsonAA.position;
var solution = jsonAA.solution;

var imageName = "crossfitChess_"+col+"_"+getImageNumber(id)+".png";
var image = getImagePath()+"\/"+col+"\/"+imageName;

return res.json({ position: position, solution : solution, image : image });
// return jsonAA;
}


Probamos el ejemplo:

¿Como probamos lo que hemos construido hasta ahora? Como es un backend de una API rest, pues simplemente invocando en el browser alguna de las direcciones de la API para ver como responde:

Ejemplo:

http://localhost:5000/chess/api/matesEn2/4

Nos debería retornar el segundo problema de la serie de "Mate en 2":  OK!
Y la imagen a la que se hace referencia en el JSON es la de un Mate en 2:


... 1. Cb5+ y luego 2. Cb7# ... Nice! Son lindos los problemas como este que empiezan con Jaque, porque no hay que pensar muchas variantes y encontras la solución rápido...






¿Que falta?

Pareciera que tenemos todo lo que buscábamos dentro de este post, pero falta subir el ejemplo a la nube, ya que hemos trabajado de forma local. De ahí que las direcciones sean con localhost:5000

Para el que necesite repasar los pasos a continuación, puede ver el post específico sobre como se creó la cuenta en heroku y se hizo el upload. O también el post anterior donde nuevamente subimos la versión previa a heroku

Subimos el proyecto a Heroku

Disculpen lo extenso del comit, pero prefiero copiarlo completo para que no se generen dudas por errores de tipeo:
MacBook-Pro-de-Pablo:node-js-getting-started pabloin$ pwd
/Users/pabloin/Desktop/_tmpAndroid/_heroku/node-js-getting-started
MacBook-Pro-de-Pablo:node-js-getting-started pabloin$ git add .
MacBook-Pro-de-Pablo:node-js-getting-started pabloin$ git commit -m "API REST para Ejercicios de Mate en 1,2,3 y 4"
[master e605c25] API REST para Ejercicios de Mate en 1,2,3 y 4
39 files changed, 159 insertions(+)
create mode 100644 public/images/mateEn1/crossfitChess_MateEn1_00000.png
create mode 100644 public/images/mateEn1/crossfitChess_MateEn1_00001.png
create mode 100644 public/images/mateEn1/crossfitChess_MateEn1_00002.png
create mode 100644 public/images/mateEn1/crossfitChess_MateEn1_00003.png
create mode 100644 public/images/mateEn1/crossfitChess_MateEn1_00004.png
create mode 100644 public/images/mateEn1/crossfitChess_MateEn1_00005.png
create mode 100644 public/images/mateEn1/crossfitChess_MateEn1_00006.png
create mode 100644 public/images/mateEn1/crossfitChess_MateEn1_00007.png
create mode 100644 public/images/mateEn1/crossfitChess_MateEn1_00008.png
create mode 100644 public/images/mateEn2/crossfitChess_MateEn2_00000.png
create mode 100644 public/images/mateEn2/crossfitChess_MateEn2_00001.png
create mode 100644 public/images/mateEn2/crossfitChess_MateEn2_00002.png
create mode 100644 public/images/mateEn2/crossfitChess_MateEn2_00003.png
create mode 100644 public/images/mateEn2/crossfitChess_MateEn2_00004.png
create mode 100644 public/images/mateEn2/crossfitChess_MateEn2_00005.png
create mode 100644 public/images/mateEn2/crossfitChess_MateEn2_00006.png
create mode 100644 public/images/mateEn2/crossfitChess_MateEn2_00007.png
create mode 100644 public/images/mateEn2/crossfitChess_MateEn2_00008.png
create mode 100644 public/images/mateEn3/crossfitChess_MateEn3_00000.png
create mode 100644 public/images/mateEn3/crossfitChess_MateEn3_00001.png
create mode 100644 public/images/mateEn3/crossfitChess_MateEn3_00002.png
create mode 100644 public/images/mateEn3/crossfitChess_MateEn3_00003.png
create mode 100644 public/images/mateEn3/crossfitChess_MateEn3_00004.png
create mode 100644 public/images/mateEn3/crossfitChess_MateEn3_00005.png
create mode 100644 public/images/mateEn3/crossfitChess_MateEn3_00006.png
create mode 100644 public/images/mateEn3/crossfitChess_MateEn3_00007.png
create mode 100644 public/images/mateEn3/crossfitChess_MateEn3_00008.png
create mode 100644 public/images/mateEn3/crossfitChess_MateEn3_00009.png
create mode 100644 public/images/mateEn3/crossfitChess_MateEn3_00010.png
create mode 100644 public/images/mateEn3/crossfitChess_MateEn3_00011.png
create mode 100644 public/images/mateEn3/crossfitChess_MateEn3_00012.png
create mode 100644 public/images/mateEn3/crossfitChess_MateEn3_00013.png
create mode 100644 public/images/mateEn3/crossfitChess_MateEn3_00014.png
create mode 100644 public/images/mateEn3/crossfitChess_MateEn3_00015.png
create mode 100644 public/images/mateEn3/crossfitChess_MateEn3_00016.png
create mode 100644 public/images/mateEn4/crossfitChess_MateEn4_00000.png
create mode 100644 public/images/mateEn4/crossfitChess_MateEn4_00001.png
create mode 100644 public/images/mateEn4/crossfitChess_MateEn4_00002.png
MacBook-Pro-de-Pablo:node-js-getting-started pabloin$ git push heroku master
Counting objects: 47, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (47/47), done.
Writing objects: 100% (47/47), 1.30 MiB | 172.00 KiB/s, done.
Total 47 (delta 3), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Using set buildpack heroku/nodejs
remote: -----> Node.js app detected
remote:
remote: -----> Creating runtime environment
remote:
remote: NPM_CONFIG_LOGLEVEL=error
remote: NPM_CONFIG_PRODUCTION=true
remote: NODE_ENV=production
remote: NODE_MODULES_CACHE=true
remote:
remote: -----> Installing binaries
remote: engines.node (package.json): 0.12.7
remote: engines.npm (package.json): unspecified (use default)
remote:
remote: Downloading and installing node 0.12.7...
remote: Using default npm version: 2.11.3
remote:
remote: -----> Restoring cache
remote: Loading 2 from cacheDirectories (default):
remote: - node_modules
remote: - bower_components (not cached - skipping)
remote:
remote: -----> Building dependencies
remote: Pruning any extraneous modules
remote: Installing node modules (package.json)
remote:
remote: -----> Caching build
remote: Clearing previous node cache
remote: Saving 2 cacheDirectories (default):
remote: - node_modules
remote: - bower_components (nothing to cache)
remote:
remote: -----> Build succeeded!
remote: ├── cool-ascii-faces@1.3.4
remote: ├── ejs@2.3.3
remote: └── express@4.13.3
remote:
remote:
remote: -----> Discovering process types
remote: Procfile declares types -> web
remote:
remote: -----> Compressing...
remote: Done: 11.8M
remote: -----> Launching...
remote: Released v13
remote: https://infinite-lowlands-19433.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/infinite-lowlands-19433.git
6ed3a45..e605c25 master -> master
MacBook-Pro-de-Pablo:node-js-getting-started pabloin$






Ultimo Paso:

Finalmente, lo último que nos queda es verificar que el backend de Heroku nos esté retornando tanto los problemas con los diagramas en formato FEN como una imagen correcta del mismo:

Listado de Problemas (Mate en 2):
https://infinite-lowlands-19433.herokuapp.com/chess/api/matesEn2

Cuarto Problema de la serie de (Mate en 2):
https://infinite-lowlands-19433.herokuapp.com/chess/api/matesEn2/4

URL de la Imagen del Cuarto Problema de la serie de (Mate en 2):
https://infinite-lowlands-19433.herokuapp.com/chess/api/matesEn2/4/img

Diagrama del Problema Nro 4 de la serie de (Mate en 2):
https://infinite-lowlands-19433.herokuapp.com/images/mateEn2/crossfitChess_mateEn2_00004.png

Verificamos que esta funcionando:



Ok, en este punto finalizamos el post, con el backend comportándose tal como lo queríamos.

En el próximo post, volveremos al desarrollo sobre Andoroid, con el front end invocando a estos servicios JSon.




Labels: , ,

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home