Este script está diseñado como contenido académico para el curso de Node.js de Fictizia.
El objetivo de este repositorio es mostrar cómo desarrollar una API Rest sencilla usando Firebase como base de datos y enriqueciendo los datos con OMBD
Este script permite al usuario introducir el nombre completo o solo parte de la película que queramos y Nodejs se encargará de buscar todos los detalles (Nombre completo, director, actores, países, argumento, poster, etc...) y actualizar la base de datos (Firebase) con esta información.
El script funciona usando un API Rest, lo que nos permite gestionar el contenido independientemente de la interfaz. En este script ya se incluye un cliente listo para que gestionemos todo desde un entorno visual (usando Bootstrap).
La parte front del proyecto se basa en la evolución del repositorio de Arvind Ravulavaru, The Jackal of Javascript. Podéis leer el artículo completo en su blog.
Para el enriquecimiento de datos con la información de las películas, utilizamos OMBD, pero a través de la librería de Misterhat
Para la gestión de los errores, he utilizado Crier.
- Backend
- Frontend
- Backend
- Frontend
Instalar dependencias
npm install
Por defecto al desplegar nuestro servidor Express renderiza una página que nos permite interactuar con el API sin salirnos del entorno visual.
Además de la lista de las películas presentes en Firebase, que se actualiza en tiempo real gracias al uso de websockets (Nodejs < -(Pillars)-> Cliente directo <- (Web Sockets) Firebase <-(API)-> Nodejs). Podemos ver los detalles de cada película en un Modal.
Además se incluye la opción de manejar el API desde la consola del navegador usando la función llamarAPI
// Hackers ID: tt0113243
// Cambiar el nombre de Hackers en la lista (método PUT, datos {nombre: "lo que sea"})
llamarAPI ("PUT", "tt0113243", "lo que sea" );
// Borrar Hackers
llamarAPI ("DELETE", "tt0113243");
// Añadir Hackers
llamarAPI ("POST", "" ,"Hackers");
Imaginemos que nuestro script está funcionando en localhost bajo el puerto 3000.
Headers CORS
El CORS está habilitado exclusivamente en la ruta del API. Gracias al sistema de enrutado que incorpora pillars, por tanto se pueden hacer peticiones a nuestra API desde otros dominios.
// CORS
var rutaApiPeliculas = new Route({
id: "peliculas",
path: "/api/peliculas/*:path",
cors: true
},
Rutas Front
- http://locahost:3000/ -> Renderizará el Index.jade y nos dejará trabajar con el entorno visual.
Rutas API
- [GET] http://locahost:3000/api/peliculas -> Muestra todas las películas de Firebase en formato .json
- [POST] http://locahost:3000/api/peliculas -> Permite añadir películas
- [GET] http://locahost:3000/api/peliculas/ -> Muestra los detalles de esa película en concreto en formato .json
- [PUT] http://locahost:3000/api/peliculas/ -> Permite actualizar el nombre de la película que se muestra en http://locahost:3000/api/peliculas
- [DELETE] http://locahost:3000/api/peliculas/ -> Borrar la película
Nota: Existe una nueva versión de Firebase, estoy trabajando en la migración. Más detalles
Este script está pensado para utilizar un Token en la escritura de datos en Firebase. La lectura de los datos no tiene restricciones. Es importante definir las reglas de seguridad de firebase de una manera compatible.
myFirebaseRef.authWithCustomToken(config.token, function(error, authData) {
if (error) {
logger.error("Error al guardar los datos en Firebase (relacionado con Token).", {
datos: error
});
} else {
logger.info("Autentificación (via Token) lograda con exito.", {
datos: authData
});
}
});
Además se recomienda hacer un indexado a la ruta "details/imbID" que es la que se usa en el front para cargar los detalles de las películas.
{
"rules": {
".read": true,
".write": true,
"nodemovies": {
".indexOn": ["details/imdbID"],
".read": true,
".write": "auth != null && auth.isAdmin == true"
}
}
}
Puerto e IP
El script está listo para funcionar en c9.io, si desea cambiarlo lo más sencillo es convertir process.env.PORT en 3000 u otro puerto y process.env.IP en "localhost". Este ajuste solo es necesario en server.js
Token y rutas
Por defecto el repositorio incorpora un archivo config.js vacio. Es necesario meter los datos correspondientes para que funcione. Es recomendable que la propiedad token sea una variable del entorno, sobretodo en entornos de producción.
Este ajuste solo es necesario en los archivos config.js (rutas y token)
var config = {
token: "",
firebaseApp: "",
firebaseAppRuta: ""
};
y publico/js/index.js (solo rutas)
var myFBAdress = "";
var serverAdress = ""; // .../api/peliculas/
El script descarga en publico/img/ todos los posters de las películas. Y solo se utilizan esas imágenes o black.jpg en su defecto. Ya que la url original provoca un error 503 al solicitarlas desde un dominio diferente (en localhost funcionan igualmente).
// Guardar los posters (Método POST)
if (pelicula.poster) {
pelicula.posterSolution = pelicula.imdb.id + ".jpg";
var file = fs.createWriteStream('./publico/img/' + pelicula.imdbID + '.jpg');
var request = http.get(pelicula.poster, function(response) {
response.pipe(file);
logger.warn("Poster de la pelicula " + pelicula.imdb.id + " guardado en /publico/img/ como " + pelicula.imdbID + ".jpg");
}).on('error', function(e) {
pelicula.posterSolution = false;
logger.error("Poster de la película " + pelicula.imdb.id + " no se pudo guardar.", {
datos: e
});
});
} else {
pelicula.posterSolution = false;
logger.error("La película " + pelicula.imdb.id + " no tiene poster asociado.");
}
y elimina los posters cuando ya no son necesarios.
// Elimina los posters (Método DELETE)
fs.unlink('./publico/img/' + req.params.id + '.jpg', function(err) {
if (err) {
if (err.errno == 34) {
logger.error("Error al borrar la imagen /publico/img/" + req.params.id + ".jpg. La imagen no existe", {
datos: err
});
} else {
logger.error("Error al borrar la imagen /publico/img/" + req.params.id + ".jpg", {
datos: err
});
}
} else {
logger.info("./publico/img/" + req.params.id + ".jpg - eliminado con exito");
}
});