Node.js

Introducción

JavaScript en servidor

Qué es nodejs

Características principales

Desventajas

trackUser =  function(userId) {
  users.findOne({userId: userId}, function(err, user) {
    var logIn = {userName: user.name, when: new Date};
    logIns.insert(logIn, function(err, done) {
      console.log('wrote log-in!');
      });
  });

Evitar el callback en el navegador

Hola Mundo en node

console.log ("Hola Mundo");

npm

Crear una libreria

Librerías en node

Microlibrerías

Funcionalidad librería

Control de versiones

Instalación de node

curl -sL <https://deb.nodesource.com/setup_5.x> | sudo -E bash -
sudo apt-get install -y nodejs
node -v
npm -v

npm

Configuración de npm

npm set init-author-name pepe
npm set init-author-email pepe@pepe.com
npm set init-author-url <http://pepe.com>
npm set init-license MIT
npm adduser

Versiones en node

npm set save-exact true

Creamos el proyecto

npm init

Listar todas las cervezas:

Ahora queremos obtener una cerveza al azar:

Subimos la librería a github

Publicamos en npm

npm publish

Probamos nuestra librería

Versiones en GitHub

Modificar librería

Versiones beta

Tests

var expect = require('chai').expect;
var cervezas = require('./index');

describe('cervezas', function () {
    describe('todas', function () {
        it('Debería ser un array de objetos', function (done) {
            // se comprueba que cumpla la condición de ser array de objetos
            done();
        });
        it('Debería incluir la cerveza Ambar', function (done) {
            // se comprueba que incluya la cerveza Ambar
            done();
        });
    });
    describe('alazar', function () {
        it('Debería mostrar una cerveza de la lista', function (done) {
            //
            done();
        });
    });
});
var expect = require('chai').expect;
var cervezas = require('./index');
var _ = require('lodash')

describe('cervezas', function () {
    describe('todas', function () {
        it('Debería ser un array de objetos', function (done) {
            expect(cervezas.todas).to.satisfy(isArrayOfObjects);
            function isArrayOfObjects(array){
                return array.every(function(item){
                    return typeof item === 'object';
                });
            }
            done();
        });
        it('Debería incluir la cerveza Ambar', function (done) {
            expect(cervezas.todas).to.satisfy(contieneAmbar);
            function contieneAmbar (array){
                return _.some(array, { 'nombre': 'ÁMBAR ESPECIAL' });
            }
            done();
        });

    });
    describe('alazar', function () {
        it('Debería mostrar un elemento de la lista de cervezas', function (done) {
            var cerveza = cervezas.alazar();
            expect(cervezas.todas).to.include(cerveza);
            done();
        });
    });
});

Automatizar tareas

Instalación Semantic Release

Versiones del software

Uso de commitizen

Cambio de versión

function alazar(unidades) { if (unidades===undefined){ return getCerveza(); } else { var misCervezas = []; for (var i = 0; i<unidades; i++) { misCervezas.push(getCerveza()); } return misCervezas; } }

- Hagamos ahora el git cz & git push y veamos como funciona todo
- Podríamos añadir un issue y hacer el fix en este commit escribiendo closes #issue en el footer del commit message.

## Git Hooks
- Son una manera de ejecutar scripts antes de que ocurra alguna acción
- Sería ideal pasar los tests antes de que se hiciera el commit
- Los Git Hooks son locales:
    - Si alguien hace un clone del repositorio, no tiene los GitHooks
    - Instalaremos un paquete de npm para hacer git hooks de forma universal

npm i -D ghooks

- Lo configuraremos en el package.json en base a la [documentación del paquete](<https://www.npmjs.com/package/ghooks>):

"config": { "ghooks": { "pre-commit": "npm test" } }

## Coverage
- Nos interesa que todo nuestro código se pruebe mediante tests.
- Necesitamos una herramienta que compruebe el código mientras se realizan los tests:

npm i -D instanbul

- Modificaremos el script de tests en el package.json:

istanbul cover -x *.test.js _mocha -- -R spec src/index.test.js

- Instanbul analizará la cobertura de todos los ficheros excepto los de test ejecutando a su vez _mocha (un wrapper de mocha proporcionado por ellos) con los tests.
- Si ejecutamos ahora *npm test* nos ofrecerá un resumen de la cobertura de nuestros tests.
- Por último nos crea una carpeta en el proyecto *coverage* donde podemos ver los datos, por ejemplo desde un navegador (fichero index.html)
- ¡Ojo, recordar poner la carpeta coverage en el .gitignore!

## Check coverage
- Podemos también evitar los commits si no hay un porcentaje de tests óptimo:

"pre-commit": "npm test && npm run check-coverage"

- Creamos el script check-coverage dentro del package.json:

"check-coverage": "istanbul check-coverage --statements 100 --branches 100 --functions 100 -lines 100"

- Podemos comprobar su ejecución desde el terminal mediante *npm run check-coverage* y añadir una función nueva sin tests, para comprobar que el check-coverage no termina con éxito.
- Lo podemos añadir también en Travis, de modo que no se haga una nueva release si no hay ciertos estándares (el test si lo hace por defecto):

script:

Gráficas

Arquitectura API REST

Creación de una API

Qué es una API

¿Para qué necesitamos una API?

Provedores de APIs

Qué significa API REST

Como funciona REST

Llamadas al API

GET <http://www.formandome.es/api/cursos/1>
200 OK HTTP/1.1
404 NOT FOUND HTTP/1.1

Creación de recursos

<http://eventos.com/api/eventos/3/comentarios>

Respuesta a la creación de recursos

Actualización de recursos

Eliminar recursos

Arquitectura REST

Reglas de una arquitectura REST

Interfaz Uniforme

Interfaz uniforme: mensajes descriptivos

Peticiones sin estado

GET mi_url/empleados/1234
DELETE mi_url/empleados/1234

Cacheable

Separación de cliente y servidor

Sistema de capas

Código bajo demanda (opcional)

Consejos para elaborar una API REST

Versiones del API

GET /v1/geocode HTTP/1.1
Host: api.geocod.io

GET /v2/geocode HTTP/1.1
Host: api.geocod.io

HTTP verbs

Nombre de los recursos

Códigos de estado

Formato de salida

GET /v1/geocode HTTP/1.1
Host: api.geocod.io
Accept: application/json

*GET /v1/geocode HTTP/1.1
Host: api.geocod.io
Accept: application/xml

Solicitudes AJAX entre dominios

Problemática

Técnicas para evitar las restricciones de seguridad

CORS

Autenticación y validación en API REST

Métodos de autenticación

- **Basada en tokens**, se confía en un token firmado que se envía al servidor en cada petición

https://juanda.gitbooks.io/webapps/content/api/cookie-token-auth.png

¿Qué es un token?

Beneficios de usar tokens

OAuth

Terminología de OAuth

Flujo en OAuth

Creación de una API

Creación de una API con node.js

Primeros pasos

Configuración de eslint

express

https://www.guru99.com/images/NodeJS/010716_0613_NodejsExpre1.png

Iniciar y testear a mano nuestra API

"start": "node app/server.js"
git status
echo "node_modules">.gitignore
git status
git add -A *
git commit -m "Primera versión API"
git push

nodemon

npm i -D nodemon
"start": "nodemon app/server.js"

Uso de enrutadores

Recibir parámetros

Parámetros por url

router.get('/:nombre', function(req, res) {
  res.json({ mensaje: '¡Hola' + req.params.nombre })
})

Parámetros por post

Ejemplo con body-parser

Rutas de nuestra API

Ruta Verbo http Descripción
/api/cervezas GET Obtenemos todas las cervezas
/api/cervezas/search?q=keyword GET Obtenemos cervezas por keyword
/api/cervezas/:id GET Obtenemos los datos de una cerveza
/api/cervezas POST Damos de alta una cerveza
/api/cervezas/:id PUT Actualizamos los datos de una cerveza
/api/cervezas/:id DELETE Borramos los datos de una cerveza
  var router = require('express').Router()
  var cervezas = require('./cervezas')

  router.use('/cervezas', cervezas)

  router.get('/', function (req, res) {
    res.status(200).json({ message: 'Estás conectado a nuestra API' })
  })

  module.exports = router
  var router = require('express').Router()
  router.get('/search', function(req, res) {
    res.json({ message: 'Vas a buscar una cerveza' })
  })
  router.get('/', function(req, res) {
    res.json({ message: 'Estás conectado a la API. Recurso: cervezas' })
  })
  router.get('/:id', function(req, res) {
    res.json({ message: 'Vas a obtener la cerveza con id ' + req.params.id })
  })
  router.post('/', function(req, res) {
    res.json({ message: 'Vas a añadir una cerveza' })
  })
  router.put('/:id', function(req, res) {
    res.json({ message: 'Vas a actualizar la cerveza con id ' + req.params.id })
  })
  router.delete('/:id', function(req, res) {
    res.json({ message: 'Vas a borrar la cerveza con id ' + req.params.id})
  })
  module.exports = router

Acceso a base de datos

Instalación de MongoDB

Inserción de datos

Instalación de Mongoose

Uso de Mongoose

Modelos

Uso de controladores

Test desde el navegador o mediante Postman

Test de la API

npm i -D mocha supertest
'use strict'
/* global describe it */
var request = require('supertest')

/*obtenemos nuestra api rest que vamos a testear*/
var app = require('../app/server')

describe('Crear una nueva cerveza', function() {
  it('Crea la cerveza retornando 201', function(done) {
    request(app)
      .post('/api/cervezas/')
      .set('Accept', 'application/json')
      .expect('Content-Type', /json/)
      .send({
        'Nombre': 'DAMN',
        'Descripción': 'Mi cerveza preferida',
        'Graduación': '10º',
        'Envase': 'Bidón',
        'Precio': '1 eurito'
      })
      .expect(201, done)
  })
})

Uso de middlewares